pwsh/dev/functions/processScopeInsightsMgOrSub.ps1 (3,795 lines of code) (raw):
function processScopeInsightsMgOrSub($mgOrSub, $mgChild, $subscriptionId, $subscriptionsMgId) {
$script:scopescnter++
$htmlScopeInsights = $null
$htmlScopeInsights = [System.Text.StringBuilder]::new()
#region ScopeInsightsBaseCollection
if ($mgOrSub -eq 'mg') {
#$startScopeInsightsPreQueryMg = Get-Date
#BLUEPRINT
$blueprintReleatedQuery = $blueprintBaseQuery.where( { $_.MgId -eq $mgChild -and [String]::IsNullOrEmpty($_.SubscriptionId) -and [String]::IsNullOrEmpty($_.BlueprintAssignmentId) } )
$blueprintsScoped = $blueprintReleatedQuery
$blueprintsScopedCount = ($blueprintsScoped).count
#Resources
$mgAllChildSubscriptions = [System.Collections.ArrayList]@()
$mgAllChildSubscriptions = foreach ($entry in $htSubscriptionsMgPath.keys) {
if (($htSubscriptionsMgPath.($entry).ParentNameChain) -contains $mgchild) {
$entry
}
}
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
$resourcesAllChildSubscriptions = [System.Collections.ArrayList]@()
foreach ($mgAllChildSubscription in $mgAllChildSubscriptions) {
foreach ($resource in ($resourcesAllGroupedBySubcriptionId.where( { $_.name -eq $mgAllChildSubscription } )).group | Sort-Object -Property type, location) {
$null = $resourcesAllChildSubscriptions.Add($resource)
}
}
$resourcesAllChildSubscriptionsArray = [System.Collections.ArrayList]@()
$grp = $resourcesAllChildSubscriptions | Group-Object -Property type, location
foreach ($resLoc in $grp) {
$cnt = 0
$ResoureTypeAndLocation = $resLoc.Name.split(',')
$resLoc.Group.count_ | ForEach-Object { $cnt += $_ }
$null = $resourcesAllChildSubscriptionsArray.Add([PSCustomObject]@{
ResourceType = $ResoureTypeAndLocation[0]
Location = $ResoureTypeAndLocation[1]
ResourceCount = $cnt
})
}
$resourcesAllChildSubscriptions.count_ | ForEach-Object { $resourcesAllChildSubscriptionTotal += $_ }
$resourcesAllChildSubscriptionResourceTypeCount = (($resourcesAllChildSubscriptions | Sort-Object -Property type -Unique) | Measure-Object).count
$resourcesAllChildSubscriptionLocationCount = (($resourcesAllChildSubscriptions | Sort-Object -Property location -Unique) | Measure-Object).count
}
#childrenMgInfo
$mgAllChildMgs = [System.Collections.ArrayList]@()
$mgAllChildMgs = foreach ($entry in $htManagementGroupsMgPath.keys) {
if (($htManagementGroupsMgPath.($entry).path) -contains $mgchild) {
$entry
}
}
$arrayPolicyAssignmentsEnrichedForThisManagementGroup = ($arrayPolicyAssignmentsEnrichedGroupedByManagementGroup.where( { $_.name -eq $mgChild } )).group
$arrayPolicyAssignmentsEnrichedForThisManagementGroupGroupedByPolicyVariant = $arrayPolicyAssignmentsEnrichedForThisManagementGroup | Group-Object -Property PolicyVariant
$arrayPolicyAssignmentsEnrichedForThisManagementGroupVariantPolicy = ($arrayPolicyAssignmentsEnrichedForThisManagementGroupGroupedByPolicyVariant.where( { $_.name -eq 'Policy' } )).group
$arrayPolicyAssignmentsEnrichedForThisManagementGroupVariantPolicySet = ($arrayPolicyAssignmentsEnrichedForThisManagementGroupGroupedByPolicyVariant.where( { $_.name -eq 'PolicySet' } )).group
if ($azAPICallConf['htParameters'].NoMDfCSecureScore -eq $false) {
if ([string]::IsNullOrEmpty(($htMgASCSecureScore).($mgChild).SecureScore) -or [string]::IsNullOrWhiteSpace(($htMgASCSecureScore).($mgChild).SecureScore)) {
$managementGroupASCPoints = 'n/a'
}
else {
$managementGroupASCPoints = ($htMgASCSecureScore).($mgChild).SecureScore
}
}
else {
$managementGroupASCPoints = "excluded (-NoMDfCSecureScore $($azAPICallConf['htParameters'].NoMDfCSecureScore))"
}
$cssClass = 'mgDetailsTable'
#$endScopeInsightsPreQueryMg = Get-Date
#Write-Host " ScopeInsights MG PreQuery processing duration: $((NEW-TIMESPAN -Start $startScopeInsightsPreQueryMg -End $endScopeInsightsPreQueryMg).TotalSeconds) seconds"
}
if ($mgOrSub -eq 'sub') {
#$startScopeInsightsPreQuerySub = Get-Date
#BLUEPRINT
$blueprintReleatedQuery = $blueprintBaseQuery.where( { $_.SubscriptionId -eq $subscriptionId -and -not [String]::IsNullOrEmpty($_.BlueprintName) } )
$blueprintsAssigned = $blueprintReleatedQuery.where( { -not [String]::IsNullOrEmpty($_.BlueprintAssignmentId) } )
$blueprintsAssignedCount = ($blueprintsAssigned).count
$blueprintsScoped = $blueprintReleatedQuery.where( { $_.BlueprintScoped -eq "/subscriptions/$subscriptionId" -and [String]::IsNullOrEmpty($_.BlueprintAssignmentId) } )
$blueprintsScopedCount = ($blueprintsScoped).count
#SubscriptionDetails
$subPath = $htSubscriptionsMgPath.($subscriptionId).pathDelimited
$subscriptionDetailsReleatedQuery = $htSubDetails.($subscriptionId).details
$subscriptionState = ($subscriptionDetailsReleatedQuery).SubscriptionState
$subscriptionQuotaId = ($subscriptionDetailsReleatedQuery).SubscriptionQuotaId
$subscriptionResourceGroupsCount = ($resourceGroupsAll.where( { $_.subscriptionId -eq $subscriptionId } )).count_
if (-not $subscriptionResourceGroupsCount) {
$subscriptionResourceGroupsCount = 0
}
$subscriptionASCPoints = ($subscriptionDetailsReleatedQuery).SubscriptionASCSecureScore
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
#Resources
$resourcesSubscription = [System.Collections.ArrayList]@()
foreach ($resource in ($resourcesAllGroupedBySubcriptionId.where( { $_.name -eq $subscriptionId } )).group | Sort-Object -Property type, location) {
$null = $resourcesSubscription.Add($resource)
}
$resourcesSubscriptionTotal = 0
$resourcesSubscription.count_ | ForEach-Object { $resourcesSubscriptionTotal += $_ }
$resourcesSubscriptionResourceTypeCount = (($resourcesSubscription | Sort-Object -Property type -Unique)).count
$resourcesSubscriptionLocationCount = (($resourcesSubscription | Sort-Object -Property location -Unique)).count
}
$arrayPolicyAssignmentsEnrichedForThisSubscription = ($arrayPolicyAssignmentsEnrichedGroupedBySubscription.where( { $_.name -eq $subscriptionId } )).group
$arrayPolicyAssignmentsEnrichedForThisSubscriptionGroupedByPolicyVariant = $arrayPolicyAssignmentsEnrichedForThisSubscription | Group-Object -Property PolicyVariant
$arrayPolicyAssignmentsEnrichedForThisSubscriptionVariantPolicy = ($arrayPolicyAssignmentsEnrichedForThisSubscriptionGroupedByPolicyVariant.where( { $_.name -eq 'Policy' } )).group
$arrayPolicyAssignmentsEnrichedForThisSubscriptionVariantPolicySet = ($arrayPolicyAssignmentsEnrichedForThisSubscriptionGroupedByPolicyVariant.where( { $_.name -eq 'PolicySet' } )).group
$arrayDefenderPlansSubscription = $defenderPlansGroupedBySub.where( { $_.Name -like "*$($subscriptionId)*" } )
$arrayUserAssignedIdentities4ResourcesSubscription = $arrayUserAssignedIdentities4Resources.where( { $_.resourceSubscriptionId -eq $subscriptionId -or $_.miSubscriptionId -eq $subscriptionId } )
$arrayUserAssignedIdentities4ResourcesSubscriptionCount = $arrayUserAssignedIdentities4ResourcesSubscription.Count
if ($subFeaturesGroupedBySubscription) {
$subscriptionFeatures = $subFeaturesGroupedBySubscription.where({ $_.name -eq $subscriptionId })
}
$cssClass = 'subDetailsTable'
#$endScopeInsightsPreQuerySub = Get-Date
#Write-Host " ScopeInsights SUB PreQuery processing duration: $((NEW-TIMESPAN -Start $startScopeInsightsPreQuerySub -End $endScopeInsightsPreQuerySub).TotalSeconds) seconds"
}
#endregion ScopeInsightsBaseCollection
if ($mgOrSub -eq 'sub') {
if ($htDefenderEmailContacts.($subscriptionDetailsReleatedQuery.subscriptionId)) {
$hlpDefenderEmailContacts = $htDefenderEmailContacts.($subscriptionDetailsReleatedQuery.subscriptionId)
$MDfCEmailNotificationsState = $hlpDefenderEmailContacts.alertNotificationsState
$MDfCEmailNotificationsSeverity = $hlpDefenderEmailContacts.alertNotificationsminimalSeverity
$MDfCEmailNotificationsRoles = $hlpDefenderEmailContacts.roles
$MDfCEmailNotificationsEmails = $hlpDefenderEmailContacts.emails
}
else {
$MDfCEmailNotificationsState = ''
$MDfCEmailNotificationsSeverity = ''
$MDfCEmailNotificationsRoles = ''
$MDfCEmailNotificationsEmails = ''
}
[void]$htmlScopeInsights.AppendLine(@"
<tr><td class="detailstd">Subscription Name: <b>$($subscriptionDetailsReleatedQuery.subscription -replace '<', '<' -replace '>', '>')</b></td></tr>
<tr><td class="detailstd">Subscription Id: <b>$($subscriptionDetailsReleatedQuery.subscriptionId)</b></td></tr>
<tr><td class="detailstd">Subscription Path: $subPath</td></tr>
<tr><td class="detailstd">State: $subscriptionState</td></tr>
<tr><td class="detailstd">QuotaId: $subscriptionQuotaId</td></tr>
<tr><td class="detailstd"><i class="fa fa-shield" aria-hidden="true"></i> Microsoft Defender for Cloud Secure Score: $subscriptionASCPoints <a class="externallink" href="https://www.youtube.com/watch?v=2EMnzxdqDhA" target="_blank" rel="noopener" rel="noopener">Video <i class="fa fa-external-link" aria-hidden="true"></i></a>, <a class="externallink" href="https://techcommunity.microsoft.com/t5/azure-security-center/security-controls-in-azure-security-center-enable-endpoint/ba-p/1624653" target="_blank" rel="noopener" rel="noopener">Blog <i class="fa fa-external-link" aria-hidden="true"></i></a>, <a class="externallink" href="https://learn.microsoft.com/azure/security-center/secure-score-security-controls#how-your-secure-score-is-calculated" target="_blank" rel="noopener" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a></td></tr>
<tr><td class="detailstd"><i class="fa fa-shield" aria-hidden="true"></i> Microsoft Defender for Cloud 'Email notifications' state: $MDfCEmailNotificationsState</td></tr>
<tr><td class="detailstd"><i class="fa fa-shield" aria-hidden="true"></i> Microsoft Defender for Cloud 'Email notifications' severity: $MDfCEmailNotificationsSeverity</td></tr>
<tr><td class="detailstd"><i class="fa fa-shield" aria-hidden="true"></i> Microsoft Defender for Cloud 'Email notifications' roles: $MDfCEmailNotificationsRoles</td></tr>
<tr><td class="detailstd"><i class="fa fa-shield" aria-hidden="true"></i> Microsoft Defender for Cloud 'Email notifications' emails: $MDfCEmailNotificationsEmails</td></tr>
<tr><td class="detailstd">
"@)
#region ScopeInsightsDefenderPlans
if ($arrayDefenderPlansSubscription) {
$defenderPlanSubscriptionDeprecatedContainerRegistry = $false
$defenderPlanSubscriptionDeprecatedKubernetesService = $false
$containerRegistryStandardCount = ($arrayDefenderPlansSubscription.Group.where( { $_.defenderPlan -eq 'ContainerRegistry' -and $_.defenderPlanTier -eq 'Standard' } )).Count
$kubernetesServiceStandardCount = ($arrayDefenderPlansSubscription.Group.where( { $_.defenderPlan -eq 'KubernetesService' -and $_.defenderPlanTier -eq 'Standard' } )).Count
if ($containerRegistryStandardCount -gt 0) {
$defenderPlanSubscriptionDeprecatedContainerRegistry = $true
}
if ($kubernetesServiceStandardCount -gt 0) {
$defenderPlanSubscriptionDeprecatedKubernetesService = $true
}
$defenderCapabilitiesSubscription = ($arrayDefenderPlansSubscription.group.defenderPlan | Sort-Object -Unique)
$tfCount = 1
$htmlTableId = "ScopeInsights_DefenderPlans_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-shield" aria-hidden="true" style="color: #0078df"></i> <span class="valignMiddle">Microsoft Defender for Cloud plans</span> <a class="externallink" href="https://learn.microsoft.com/azure/defender-for-cloud/enhanced-security-features-overview" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a></button>
<div class="content contentSISub">
"@)
if ($defenderPlanSubscriptionDeprecatedContainerRegistry) {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Using deprecated plan 'Container registries' <a class="externallink" href="https://learn.microsoft.com/azure/defender-for-cloud/release-notes#microsoft-defender-for-containers-plan-released-for-general-availability-ga" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
'@)
}
if ($defenderPlanSubscriptionDeprecatedKubernetesService) {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Using deprecated plan 'Kubernetes' <a class="externallink" href="https://learn.microsoft.com/azure/defender-for-cloud/release-notes#microsoft-defender-for-containers-plan-released-for-general-availability-ga" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
'@)
}
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Plan</th>
<th>Tier</th>
</tr>
</thead>
<tbody>
"@)
foreach ($plan in $arrayDefenderPlansSubscription.Group | Sort-Object -Property defenderPlan) {
if (($plan.defenderPlan -eq 'ContainerRegistry' -and $plan.defenderPlanTier -eq 'Standard') -or ($plan.defenderPlan -eq 'KubernetesService' -and $plan.defenderPlanTier -eq 'Standard')) {
$thisDefenderPlan = "<i class=`"fa fa-exclamation-triangle`" aria-hidden=`"true`"></i> $($plan.defenderPlan)"
}
else {
$thisDefenderPlan = $plan.defenderPlan
}
[void]$htmlScopeInsights.AppendLine(@"
<tr>
<td>$($thisDefenderPlan)</td>
<td>$($plan.defenderPlanTier)</td>
</tr>
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_1: 'select',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'@)
$cnt = 0
foreach ($defenderCapability in $defenderCapabilitiesSubscription) {
$cnt++
if ($defenderCapabilitiesSubscription.Count -eq $cnt) {
[void]$htmlScopeInsights.AppendLine(@'
'caseinsensitivestring'
'@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
'caseinsensitivestring',
'@)
}
}
[void]$htmlScopeInsights.AppendLine(@"
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
$subscriptionSkippedMDfC = $arrayDefenderPlansSubscriptionsSkipped.where( { $_.subscriptionId -eq $subscriptionId } )
if ($subscriptionSkippedMDfC.Count -gt 0) {
if ($subscriptionSkippedMDfC.reason -eq 'SubScriptionNotRegistered') {
[void]$htmlScopeInsights.AppendLine(@"
<i class=`"fa fa-shield`" aria-hidden=`"true`"></i> Microsoft Defender for Cloud plans - Subscription skipped ($($subscriptionSkippedMDfC.reason)) (ResourceProvider: Microsoft.Security) <a class=`"externallink`" href=`"https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider`" target=`"_blank`" rel=`"noopener`">learn <i class=`"fa fa-external-link`" aria-hidden=`"true`"></i></a>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class=`"fa fa-shield`" aria-hidden=`"true`"></i> Microsoft Defender for Cloud plans - Subscription skipped ($($subscriptionSkippedMDfC.reason))
"@)
}
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-shield" aria-hidden="true"></i> No Microsoft Defender for Cloud plans <a class="externallink" href="https://learn.microsoft.com/azure/defender-for-cloud/enhanced-security-features-overview" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
'@)
}
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsDefenderPlans
#region ScopeInsightsDiganosticsSubscription
if (($htDiagnosticSettingsMgSub).sub.($subscriptionId)) {
$diagnosticsSubCount = (($htDiagnosticSettingsMgSub).sub.($subscriptionId).Values.Count)
$tfCount = $diagnosticsSubCount
$htmlTableId = "ScopeInsights_DiagnosticsSub_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$diagnosticsSubCount Subscription Diagnostic settings</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Diagnostic setting</th>
<th>Target</th>
<th>Target Id</th>
"@)
foreach ($logCategory in $diagnosticSettingsSubCategories) {
[void]$htmlScopeInsights.AppendLine(@"
<th>$logCategory</th>
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</tr>
</thead>
<tbody>
'@)
$htmlScopeInsightsDiagnosticsSub = $null
$htmlScopeInsightsDiagnosticsSub = foreach ($entry in ($htDiagnosticSettingsMgSub).sub.($subscriptionId).keys | Sort-Object) {
foreach ($diagset in ($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.keys | Sort-Object) {
@"
<tr>
<td>$(($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.$diagset.DiagnosticSettingName)</td>
<td>$(($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.$diagset.DiagnosticTargetType)</td>
<td>$(($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.$diagset.DiagnosticTargetId)</td>
"@
foreach ($logCategory in $diagnosticSettingsSubCategories) {
if (($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.$diagset.DiagnosticCategoriesHt.($logCategory)) {
@"
<td>$(($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.$diagset.DiagnosticCategoriesHt.($logCategory))</td>
"@
}
else {
@'
<td>n/a</td>
'@
}
}
@'
</tr>
'@
}
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsDiagnosticsSub)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_1: 'select',
'@)
$cnt = 2
foreach ($logCategory in $diagnosticSettingsSubCategories) {
$cnt++
[void]$htmlScopeInsights.AppendLine(@"
col_$($cnt): 'select',
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'@)
$cnt = 0
foreach ($logCategory in $diagnosticSettingsSubCategories) {
$cnt++
if ($diagnosticSettingsSubCategories.Count -eq $cnt) {
[void]$htmlScopeInsights.AppendLine(@'
'caseinsensitivestring'
'@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
'caseinsensitivestring',
'@)
}
}
[void]$htmlScopeInsights.AppendLine(@"
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No Subscription Diagnostic settings <a class="externallink" href="https://learn.microsoft.com/azure/azure-monitor/essentials/quick-collect-activity-log-portal#create-diagnostic-setting" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsDiganosticsSubscription
#Tags
#region ScopeInsightsTags
$tagsSubscriptionCount = ($htSubscriptionTags.$subscriptionId.Keys).count
if ($tagsSubscriptionCount -gt 0) {
$tfCount = $tagsSubscriptionCount
$htmlTableId = "ScopeInsights_Tags_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$tagsSubscriptionCount Subscription Tags | Limit: ($tagsSubscriptionCount/$LimitTagsSubscription)</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">Tag Name</th>
<th>Tag Value</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsTags = $null
$htmlScopeInsightsTags = foreach ($tag in (($htSubscriptionTags).($subscriptionId)).keys | Sort-Object) {
@"
<tr>
<td>$tag</td>
<td>$($htSubscriptionTags.$subscriptionId[$tag])</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsTags)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $tagsSubscriptionCount Subscription Tags
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsTags
#TagNameUsage
#region ScopeInsightsTagNameUsage
$arrayTagListSubscription = [System.Collections.ArrayList]@()
foreach ($tagScope in $htSubscriptionTagList.($subscriptionId).keys) {
foreach ($tagScopeTagName in $htSubscriptionTagList.($subscriptionId).$tagScope.keys) {
$null = $arrayTagListSubscription.Add([PSCustomObject]@{
Scope = $tagScope
TagName = ($tagScopeTagName)
TagCount = $htSubscriptionTagList.($subscriptionId).($tagScope).($tagScopeTagName)
})
}
}
$tagsUsageCount = ($arrayTagListSubscription).Count
if ($tagsUsageCount -gt 0) {
$tagNamesUniqueCount = ($arrayTagListSubscription | Sort-Object -Property TagName -Unique).Count
$tagNamesUsedInScopes = ($arrayTagListSubscription | Sort-Object -Property Scope -Unique).scope -join "$($CsvDelimiterOpposite) "
$tfCount = $tagsUsageCount
$htmlTableId = "ScopeInsights_TagNameUsage_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">Tag Name Usage ($tagNamesUniqueCount unique Tag Names applied at $($tagNamesUsedInScopes)</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">Resource naming and tagging decision guide</span> <a class="externallink" href="https://learn.microsoft.com/azure/cloud-adoption-framework/decision-guides/resource-tagging" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Scope</th>
<th>TagName</th>
<th>Count</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsTagsUsage = $null
$htmlScopeInsightsTagsUsage = foreach ($tagEntry in $arrayTagListSubscription | Sort-Object Scope, TagName -CaseSensitive) {
@"
<tr>
<td>$($tagEntry.Scope)</td>
<td>$($tagEntry.TagName)</td>
<td>$($tagEntry.TagCount)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsTagsUsage)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_0: 'multiple',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'number'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> Tag Name Usage ($tagsUsageCount Tags) <a class="externallink" href="https://learn.microsoft.com/azure/cloud-adoption-framework/decision-guides/resource-tagging" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsTagNameUsage
#Consumption
#$startScopeInsightsConsumptionSub = Get-Date
#region ScopeInsightsConsumptionSub
if ($azAPICallConf['htParameters'].DoAzureConsumption -eq $true) {
if ($htAzureConsumptionSubscriptions.($subscriptionId).ConsumptionData) {
$consumptionData = $htAzureConsumptionSubscriptions.($subscriptionId).ConsumptionData
$arrayTotalCostSummarySub = @()
$arrayConsumptionData = [System.Collections.ArrayList]@()
$totalCost = 0
$currency = $htAzureConsumptionSubscriptions.($subscriptionId).Currency
$consumedServiceCount = ($consumptionData.ResourceType | Sort-Object -Unique | Measure-Object).Count
$resourceCount = ($consumptionData.ResourceId | Sort-Object -Unique | Measure-Object).Count
$subConsumptionDataGrouped = $consumptionData | Group-Object -Property ResourceType, ChargeType, MeterCategory
foreach ($consumptionline in $subConsumptionDataGrouped) {
$costConsumptionLine = ($consumptionline.group.PreTaxCost | Measure-Object -Sum).Sum
if ([math]::Round($costConsumptionLine, 2) -eq 0) {
$cost = $costConsumptionLine.ToString('0.0000')
}
else {
$cost = [math]::Round($costConsumptionLine, 2).ToString('0.00')
}
$null = $arrayConsumptionData.Add([PSCustomObject]@{
ResourceType = ($consumptionline.name).split(', ')[0]
ConsumedServiceChargeType = ($consumptionline.name).split(', ')[1]
ConsumedServiceCategory = ($consumptionline.name).split(', ')[2]
ConsumedServiceInstanceCount = $consumptionline.Count
ConsumedServiceCost = $cost #[decimal]$cost
ConsumedServiceCurrency = $currency
})
$totalCost = $htAzureConsumptionSubscriptions.($subscriptionId).TotalCost
}
if ([math]::Round($totalCost, 2) -eq 0) {
$totalCost = $totalCost
}
else {
$totalCost = [math]::Round($totalCost, 2).ToString('0.00')
}
$arrayTotalCostSummarySub += "$($totalCost) $($currency) generated by $($resourceCount) Resources ($($consumedServiceCount) ResourceTypes)"
$tfCount = ($arrayConsumptionData | Measure-Object).Count
$htmlTableId = "ScopeInsights_Consumption_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-credit-card blue" aria-hidden="true"></i> <span class="valignMiddle">Total cost $($arrayTotalCostSummarySub -join ', ') $AzureConsumptionPeriod days ($azureConsumptionStartDate - $azureConsumptionEndDate)</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>ChargeType</th>
<th>ResourceType</th>
<th>Category</th>
<th>ResourceCount</th>
<th>Cost ($($AzureConsumptionPeriod)d)</th>
<th>Currency</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsConsumptionSub = $null
$htmlScopeInsightsConsumptionSub = foreach ($consumptionLine in $arrayConsumptionData) {
@"
<tr>
<td>$($consumptionLine.ConsumedServiceChargeType)</td>
<td>$($consumptionLine.ResourceType)</td>
<td>$($consumptionLine.ConsumedServiceCategory)</td>
<td>$($consumptionLine.ConsumedServiceInstanceCount)</td>
<td>$($consumptionLine.ConsumedServiceCost)</td>
<td>$($currency)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsConsumptionSub)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId=1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'number',
'number',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-credit-card" aria-hidden="true"></i> No Consumption data available
'@)
}
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-credit-card" aria-hidden="true"></i> No Consumption data available as switch parameter -DoAzureConsumption was not applied
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsConsumptionSub
#$endScopeInsightsConsumptionSub = Get-Date
#Write-Host " **ScopeInsightsConsumptionSub data duration: $((NEW-TIMESPAN -Start $startScopeInsightsConsumptionSub -End $endScopeInsightsConsumptionSub).TotalSeconds) seconds"
#ResourceGroups
#region ScopeInsightsResourceGroups
if ($subscriptionResourceGroupsCount -gt 0) {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-check-circle" aria-hidden="true"></i> $subscriptionResourceGroupsCount Resource Groups | Limit: ($subscriptionResourceGroupsCount/$LimitResourceGroups)
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $subscriptionResourceGroupsCount Resource Groups
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsResourceGroups
#ResourceProvider
#region ScopeInsightsResourceProvidersDetailed
if ($azAPICallConf['htParameters'].NoResourceProvidersAtAll -eq $false) {
if ($azAPICallConf['htParameters'].NoResourceProvidersDetailed -eq $false) {
if (($htResourceProvidersAll).($subscriptionId)) {
$tfCount = ($htResourceProvidersAll).($subscriptionId).Providers.Count
$htmlTableId = "ScopeInsights_ResourceProvider_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">Resource Providers Detailed</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Provider</th>
<th>State</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsResourceProvidersDetailed = $null
$htmlScopeInsightsResourceProvidersDetailed = foreach ($provider in ($htResourceProvidersAll).($subscriptionId).Providers) {
@"
<tr>
<td>$($provider.namespace)</td>
<td>$($provider.registrationState)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsResourceProvidersDetailed)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId=1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_1: 'select',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $(($htResourceProvidersAll.Keys).count) Resource Providers
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
}
#endregion ScopeInsightsResourceProvidersDetailed
#region ScopeInsightsSubscriptionFeatures
if ($subscriptionFeatures) {
$subscriptionFeaturesCount = $subscriptionFeatures.Group.Count
$tfCount = $subscriptionFeaturesCount
$htmlTableId = "ScopeInsights_SubscriptionFeatures_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-cube" aria-hidden="true" style="color: #0078df"></i> <span class="valignMiddle">$tfCount enabled Subscription Features</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">Set up preview features in Azure subscription</span> <a class="externallink" href="https://learn.microsoft.com/azure/azure-resource-manager/management/preview-features" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Feature</th>
</tr>
</thead>
<tbody>
"@)
foreach ($feature in $subscriptionFeatures.Group | Sort-Object -Property feature) {
[void]$htmlScopeInsights.AppendLine(@"
<tr><td>$($feature.feature)</td></tr>
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_types: [
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> 0 enabled Subscription Features <a class="externallink" href="https://learn.microsoft.com/azure/azure-resource-manager/management/preview-features" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsSubscriptionFeatures
#ResourceLocks
#region ScopeInsightsResourceLocks
if ($htResourceLocks.($subscriptionId)) {
$tfCount = 6
$htmlTableId = "ScopeInsights_ResourceLocks_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
$subscriptionLocksCannotDeleteCount = $htResourceLocks.($subscriptionId).SubscriptionLocksCannotDeleteCount
$subscriptionLocksReadOnlyCount = $htResourceLocks.($subscriptionId).SubscriptionLocksReadOnlyCount
$resourceGroupsLocksCannotDeleteCount = $htResourceLocks.($subscriptionId).ResourceGroupsLocksCannotDeleteCount
$resourceGroupsLocksReadOnlyCount = $htResourceLocks.($subscriptionId).ResourceGroupsLocksReadOnlyCount
$resourcesLocksCannotDeleteCount = $htResourceLocks.($subscriptionId).ResourcesLocksCannotDeleteCount
$resourcesLocksReadOnlyCount = $htResourceLocks.($subscriptionId).ResourcesLocksReadOnlyCount
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">Resource Locks</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">Considerations before applying locks</span> <a class="externallink" href="https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources#considerations-before-applying-locks" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Lock scope</th>
<th>Lock type</th>
<th>presence</th>
</tr>
</thead>
<tbody>
<tr><td>Subscription</td><td>CannotDelete</td><td>$($subscriptionLocksCannotDeleteCount)</td></tr>
<tr><td>Subscription</td><td>ReadOnly</td><td>$($subscriptionLocksReadOnlyCount)</td></tr>
<tr><td>ResourceGroup</td><td>CannotDelete</td><td>$($resourceGroupsLocksCannotDeleteCount)</td></tr>
<tr><td>ResourceGroup</td><td>ReadOnly</td><td>$($resourceGroupsLocksReadOnlyCount)</td></tr>
<tr><td>Resource</td><td>CannotDelete</td><td>$($resourcesLocksCannotDeleteCount)</td></tr>
<tr><td>Resource</td><td>ReadOnly</td><td>$($resourcesLocksReadOnlyCount)</td></tr>
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_0: 'select',
col_1: 'select',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'number'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> 0 Resource Locks <a class="externallink" href="https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources#considerations-before-applying-locks" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsResourceLocks
}
#MgChildInfo
#region ScopeInsightsManagementGroups
if ($mgOrSub -eq 'mg') {
[void]$htmlScopeInsights.AppendLine(@"
<tr><td class="detailstd">$(($mgAllChildMgs).count -1) ManagementGroups below this scope</td></tr>
<tr><td class="detailstd">$(($mgAllChildSubscriptions).count) Subscriptions below this scope</td></tr>
<tr><td class="detailstd"><i class="fa fa-shield" aria-hidden="true"></i> Microsoft Defender for Cloud Secure Score: $managementGroupASCPoints <a class="externallink" href="https://www.youtube.com/watch?v=2EMnzxdqDhA" target="_blank" rel="noopener">Video <i class="fa fa-external-link" aria-hidden="true"></i></a>, <a class="externallink" href="https://techcommunity.microsoft.com/t5/azure-security-center/security-controls-in-azure-security-center-enable-endpoint/ba-p/1624653" target="_blank" rel="noopener">Blog <i class="fa fa-external-link" aria-hidden="true"></i></a>, <a class="externallink" href="https://learn.microsoft.com/azure/security-center/secure-score-security-controls#how-your-secure-score-is-calculated" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a></td></tr>
<tr><td class="detailstd">
"@)
#region ScopeInsightsDiagnosticsMg
if (($htDiagnosticSettingsMgSub).mg.($mgChild)) {
$diagnosticsMgCount = (($htDiagnosticSettingsMgSub).mg.($mgChild).Values.Count)
$tfCount = $diagnosticsMgCount
$htmlTableId = "ScopeInsights_DiagnosticsMg_$($mgChild -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$diagnosticsMgCount Management Group Diagnostic settings</span></button>
<div class="content contentSIMG">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Diagnostic setting</th>
<th>Target</th>
<th>Target Id</th>
"@)
foreach ($logCategory in $diagnosticSettingsMgCategories) {
[void]$htmlScopeInsights.AppendLine(@"
<th>$logCategory</th>
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</tr>
</thead>
<tbody>
'@)
$htmlScopeInsightsDiagnosticsMg = $null
$htmlScopeInsightsDiagnosticsMg = foreach ($entry in ($htDiagnosticSettingsMgSub).mg.($mgChild).keys | Sort-Object) {
foreach ($diagset in ($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.keys | Sort-Object) {
@"
<tr>
<td>$(($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.$diagset.DiagnosticSettingName)</td>
<td>$(($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.$diagset.DiagnosticTargetType)</td>
<td>$(($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.$diagset.DiagnosticTargetId)</td>
"@
foreach ($logCategory in $diagnosticSettingsMgCategories) {
if (($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.$diagset.DiagnosticCategoriesHt.($logCategory)) {
@"
<td>$(($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.$diagset.DiagnosticCategoriesHt.($logCategory))</td>
"@
}
else {
@'
<td>n/a</td>
'@
}
}
@'
</tr>
'@
}
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsDiagnosticsMg)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_1: 'select',
'@)
$cnt = 2
foreach ($logCategory in $diagnosticSettingsMgCategories) {
$cnt++
[void]$htmlScopeInsights.AppendLine(@"
col_$($cnt): 'select',
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'@)
$cnt = 0
foreach ($logCategory in $diagnosticSettingsMgCategories) {
$cnt++
if ($diagnosticSettingsMgCategories.Count -eq $cnt) {
[void]$htmlScopeInsights.AppendLine(@'
'caseinsensitivestring'
'@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
'caseinsensitivestring',
'@)
}
}
[void]$htmlScopeInsights.AppendLine(@"
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No Management Group Diagnostic settings <a class="externallink" href="https://learn.microsoft.com/rest/api/monitor/managementgroupdiagnosticsettings/createorupdate" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a>
'@)
}
#endregion ScopeInsightsDiagnosticsMg
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#$startScopeInsightsConsumptionMg = Get-Date
#region ScopeInsightsConsumptionMg
if ($azAPICallConf['htParameters'].DoAzureConsumption -eq $true) {
if ($allConsumptionDataCount -gt 0) {
$consumptionData = $htManagementGroupsCost.($mgchild).consumptionDataSubscriptions
if (($consumptionData | Measure-Object).Count -gt 0) {
$arrayTotalCostSummaryMg = @()
$arrayConsumptionData = [System.Collections.ArrayList]@()
$consumptionDataGroupedByCurrency = $consumptionData | Group-Object -Property Currency
foreach ($currency in $consumptionDataGroupedByCurrency) {
$totalCost = 0
$tenantSummaryConsumptionDataGrouped = $currency.group | Group-Object -Property ResourceType, ChargeType, MeterCategory
$subsCount = ($tenantSummaryConsumptionDataGrouped.group.subscriptionId | Sort-Object -Unique).Count
$consumedServiceCount = ($tenantSummaryConsumptionDataGrouped.group.ResourceType | Sort-Object -Unique).Count
$resourceCount = ($tenantSummaryConsumptionDataGrouped.group.ResourceId | Sort-Object -Unique).Count
foreach ($consumptionline in $tenantSummaryConsumptionDataGrouped) {
$costConsumptionLine = ($consumptionline.group.PreTaxCost | Measure-Object -Sum).Sum
if ([math]::Round($costConsumptionLine, 2) -eq 0) {
$cost = $costConsumptionLine.ToString('0.0000')
}
else {
$cost = [math]::Round($costConsumptionLine, 2).ToString('0.00')
}
$null = $arrayConsumptionData.Add([PSCustomObject]@{
ResourceType = ($consumptionline.name).split(', ')[0]
ConsumedServiceChargeType = ($consumptionline.name).split(', ')[1]
ConsumedServiceCategory = ($consumptionline.name).split(', ')[2]
ConsumedServiceInstanceCount = $consumptionline.Count
ConsumedServiceCost = $cost #[decimal]$cost
ConsumedServiceSubscriptions = ($consumptionline.group.SubscriptionId | Sort-Object -Unique).Count
ConsumedServiceCurrency = $currency.Name
})
$totalCost = $totalCost + $costConsumptionLine
}
if ([math]::Round($totalCost, 2) -eq 0) {
$totalCost = $totalCost.ToString('0.0000')
}
else {
$totalCost = [math]::Round($totalCost, 2).ToString('0.00')
}
$arrayTotalCostSummaryMg += "$($totalCost) $($currency.Name) generated by $($resourceCount) Resources ($($consumedServiceCount) ResourceTypes) in $($subsCount) Subscriptions"
}
$tfCount = ($arrayConsumptionData).Count
$htmlTableId = "ScopeInsights_Consumption_$($mgChild -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-credit-card blue" aria-hidden="true"></i> <span class="valignMiddle">Total cost $($arrayTotalCostSummaryMg -join "$CsvDelimiterOpposite ") $AzureConsumptionPeriod days ($azureConsumptionStartDate - $azureConsumptionEndDate)</span></button>
<div class="content contentSIMG">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV
<a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> |
<a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>ChargeType</th>
<th>ResourceType</th>
<th>Category</th>
<th>ResourceCount</th>
<th>Cost ($($AzureConsumptionPeriod)d)</th>
<th>Currency</th>
<th>Subscriptions</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsConsumptionMg = $null
$htmlScopeInsightsConsumptionMg = foreach ($consumptionLine in $arrayConsumptionData) {
@"
<tr>
<td>$($consumptionLine.ConsumedServiceChargeType)</td>
<td>$($consumptionLine.ResourceType)</td>
<td>$($consumptionLine.ConsumedServiceCategory)</td>
<td>$($consumptionLine.ConsumedServiceInstanceCount)</td>
<td>$($consumptionLine.ConsumedServiceCost)</td>
<td>$($consumptionLine.ConsumedServiceCurrency)</td>
<td>$($consumptionLine.ConsumedServiceSubscriptions)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsConsumptionMg)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId=1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'number',
'number',
'caseinsensitivestring',
'number'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-credit-card" aria-hidden="true"></i> No Consumption data available for Subscriptions under this ManagementGroup
'@)
}
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-credit-card" aria-hidden="true"></i> No Consumption data available
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-credit-card" aria-hidden="true"></i> <span class="valignMiddle">No Consumption data available as switch parameter -DoAzureConsumption was not applied</span>
'@)
}
#endregion ScopeInsightsConsumptionMg
#$endScopeInsightsConsumptionMg = Get-Date
#Write-Host " ++ScopeInsightsConsumptionMg duration: ($((NEW-TIMESPAN -Start $startScopeInsightsConsumptionMg -End $endScopeInsightsConsumptionMg).TotalSeconds) seconds)"
}
#endregion ScopeInsightsManagementGroups
#ScopeInsightsResources
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
#resources
#region ScopeInsightsResources
if ($mgOrSub -eq 'mg') {
if ($resourcesAllChildSubscriptionLocationCount -gt 0) {
$tfCount = ($resourcesAllChildSubscriptionsArray).count
$htmlTableId = "ScopeInsights_Resources_$($mgChild -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$resourcesAllChildSubscriptionResourceTypeCount ResourceTypes ($resourcesAllChildSubscriptionTotal Resources) in $resourcesAllChildSubscriptionLocationCount Locations (all Subscriptions below this scope)</span></button>
<div class="content contentSIMG">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">ResourceType</th>
<th>Location</th>
<th>Count</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsResources = $null
$htmlScopeInsightsResources = foreach ($resourceAllChildSubscriptionResourceTypePerLocation in $resourcesAllChildSubscriptionsArray | Sort-Object @{Expression = { $_.ResourceType } }, @{Expression = { $_.location } }) {
@"
<tr>
<td>$($resourceAllChildSubscriptionResourceTypePerLocation.ResourceType)</td>
<td>$($resourceAllChildSubscriptionResourceTypePerLocation.location)</td>
<td>$($resourceAllChildSubscriptionResourceTypePerLocation.ResourceCount)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsResources)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'number'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $resourcesAllChildSubscriptionResourceTypeCount ResourceTypes (all Subscriptions below this scope)
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
if ($mgOrSub -eq 'sub') {
if ($resourcesSubscriptionResourceTypeCount -gt 0) {
$tfCount = ($resourcesSubscription).Count
$htmlTableId = "ScopeInsights_Resources_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$resourcesSubscriptionResourceTypeCount ResourceTypes ($resourcesSubscriptionTotal Resources) in $resourcesSubscriptionLocationCount Locations</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">ResourceType</th>
<th>Location</th>
<th>Count</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsResources = $null
$htmlScopeInsightsResources = foreach ($resourceSubscriptionResourceTypePerLocation in $resourcesSubscription | Sort-Object @{Expression = { $_.type } }, @{Expression = { $_.location } }, @{Expression = { $_.count_ } }) {
@"
<tr>
<td>$($resourceSubscriptionResourceTypePerLocation.type)</td>
<td>$($resourceSubscriptionResourceTypePerLocation.location)</td>
<td>$($resourceSubscriptionResourceTypePerLocation.count_)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsResources)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'number'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $resourcesSubscriptionResourceTypeCount ResourceTypes
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
#endregion ScopeInsightsResources
}
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
#region ScopeInsightsCAFResourceNamingALL
if ($mgOrSub -eq 'sub') {
$resourcesIdsAllCAFNamingRelevantThisSubscription = $resourcesIdsAllCAFNamingRelevantGroupedBySubscription.where({ $_.Name -eq $subscriptionId })
if ($resourcesIdsAllCAFNamingRelevantThisSubscription) {
$resourcesIdsAllCAFNamingRelevantThisSubscriptionGroupedByType = $resourcesIdsAllCAFNamingRelevantThisSubscription.Group | Group-Object -Property type
$resourcesIdsAllCAFNamingRelevantThisSubscriptionGroupedByTypeCount = ($resourcesIdsAllCAFNamingRelevantThisSubscriptionGroupedByType | Measure-Object).Count
$tfCount = $resourcesIdsAllCAFNamingRelevantThisSubscriptionGroupedByTypeCount
$htmlTableId = "ScopeInsights_CAFResourceNamingALL_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-star-o" aria-hidden="true" style="color: #0078df"></i> <span class="valignMiddle">CAF Naming Recommendation Compliance</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">CAF - Recommended abbreviations for Azure resource types</span> <a class="externallink" href="https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> Resource details can be found in the CSV output *_ResourcesAll.csv<br>
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>ResourceType</th>
<th>Recommendation</th>
<th>ResourceFriendlyName</th>
<th>passed</th>
<th>failed</th>
<th>passed percentage</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsCAFResourceNamingALL = $null
$htmlScopeInsightsCAFResourceNamingALL = foreach ($entry in $resourcesIdsAllCAFNamingRelevantThisSubscriptionGroupedByType) {
$resourceTypeGroupedByCAFResourceNamingResult = $entry.Group | Group-Object -Property cafResourceNamingResult, cafResourceNaming
if ($entry.Group.cafResourceNaming.Count -gt 1) {
$namingConvention = ($entry.Group.cafResourceNaming)[0]
$namingConventionFriendlyName = ($entry.Group.cafResourceNamingFriendlyName)[0]
}
else {
$namingConvention = $entry.Group.cafResourceNaming
$namingConventionFriendlyName = $entry.Group.cafResourceNamingFriendlyName
}
$passed = 0
$failed = 0
foreach ($result in $resourceTypeGroupedByCAFResourceNamingResult) {
$resultNameSplitted = $result.Name -split ', '
if ($resultNameSplitted[0] -eq 'passed') {
$passed = $result.Count
}
if ($resultNameSplitted[0] -eq 'failed') {
$failed = $result.Count
}
}
if ($passed -gt 0) {
$percentage = [math]::Round(($passed / ($passed + $failed) * 100), 2)
}
else {
$percentage = 0
}
@"
<tr>
<td>$($entry.Name)</td>
<td>$($namingConvention)</td>
<td>$($namingConventionFriendlyName)</td>
<td>$($passed)</td>
<td>$($failed)</td>
<td>$($percentage)%</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsCAFResourceNamingALL)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'number',
'number',
'number'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No CAF Naming Recommendation Compliance data available
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
#endregion ScopeInsightsCAFResourceNamingALL
}
#region ScopeInsightsOrphanedResources
if ($mgOrSub -eq 'sub') {
if ($arrayOrphanedResourcesGroupedBySubscription) {
$orphanedResourcesThisSubscription = $arrayOrphanedResourcesGroupedBySubscription.where({ $_.Name -eq $subscriptionId })
if ($orphanedResourcesThisSubscription) {
$orphanedResourcesThisSubscriptionCount = $orphanedResourcesThisSubscription.Group.count
if ($azAPICallConf['htParameters'].DoAzureConsumption -eq $true) {
$orphanedIncludingCost = $true
$hintTableTH = " ($($AzureConsumptionPeriod) days)"
$orphanedResourcesThisSubscriptionGroupedByType = $orphanedResourcesThisSubscription.Group | Group-Object -Property type, intent, currency
$orphanedResourcesThisSubscriptionGroupedByTypeCount = ($orphanedResourcesThisSubscriptionGroupedByType | Measure-Object).Count
}
else {
$orphanedIncludingCost = $false
$hintTableTH = ''
$orphanedResourcesThisSubscriptionGroupedByType = $orphanedResourcesThisSubscription.Group | Group-Object -Property type, intent
$orphanedResourcesThisSubscriptionGroupedByTypeCount = ($orphanedResourcesThisSubscriptionGroupedByType | Measure-Object).Count
}
$tfCount = $orphanedResourcesThisSubscriptionGroupedByTypeCount
$htmlTableId = "ScopeInsights_OrphanedResources_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-trash-o" aria-hidden="true" style="color: #0078df"></i> <span class="valignMiddle">$orphanedResourcesThisSubscriptionCount Cost optimization & cleanup ($orphanedResourcesThisSubscriptionGroupedByTypeCount ResourceTypes)</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">'Azure Orphan Resources' ARG queries and workbooks</span> <a class="externallink" href="https://github.com/dolevshor/azure-orphan-resources" target="_blank" rel="noopener">GitHub <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> Resource details can be found in the CSV output *_ResourcesCostOptimizationAndCleanup.csv<br>
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>ResourceType</th>
<th>Resource count</th>
<th>Intent</th>
<th>Cost$($hintTableTH)</th>
<th>Currency</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsOrphanedResources = $null
$htmlScopeInsightsOrphanedResources = foreach ($resourceType in $orphanedResourcesThisSubscriptionGroupedByType | Sort-Object -Property Name) {
if ($orphanedIncludingCost) {
if (($resourceType.Group[0].Intent) -like 'cost savings*') {
$orphCost = ($resourceType.Group.Cost | Measure-Object -Sum).Sum
if ($orphCost -eq 0) {
$orphCost = ''
}
$orphCurrency = $resourceType.Group[0].Currency
}
else {
$orphCost = ''
$orphCurrency = ''
}
}
else {
if (($resourceType.Group.Intent | Get-Unique) -like 'cost savings*') {
$orphCost = "<span class=`"info`">use parameter <b>-DoAzureConsumption</b> to show potential savings</span>"
$orphCurrency = ''
}
else {
$orphCost = ''
$orphCurrency = ''
}
}
@"
<tr>
<td>$(($resourceType.Name -split ',')[0])</td>
<td>$($resourceType.Group.Count)</td>
<td>$($resourceType.Group[0].Intent)</td>
<td>$($orphCost)</td>
<td>$($orphCurrency)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsOrphanedResources)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_0: 'multiple',
col_2: 'select',
col_4: 'select',
col_types: [
'caseinsensitivestring',
'number',
'caseinsensitivestring',
'number',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No cost optimization & cleanup
'@)
}
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No cost optimization & cleanup
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
#endregion ScopeInsightsOrphanedResources
#ScopeInsightsDiagnosticsCapable
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
#resourcesDiagnosticsCapable
#region ScopeInsightsDiagnosticsCapable
if ($mgOrSub -eq 'mg') {
$resourceTypesUnique = ($resourcesAllChildSubscriptions | Select-Object type -Unique).type
$resourceTypesSummarizedArray = [System.Collections.ArrayList]@()
foreach ($resourceTypeUnique in $resourceTypesUnique) {
$resourcesTypeCountTotal = 0
($resourcesAllChildSubscriptions.where( { $_.type -eq $resourceTypeUnique } )).count_ | ForEach-Object { $resourcesTypeCountTotal += $_ }
$dataFromResourceTypesDiagnosticsArray = $resourceTypesDiagnosticsArray.where( { $_.ResourceType -eq $resourceTypeUnique } )
if ($dataFromResourceTypesDiagnosticsArray.Metrics -eq $true -or $dataFromResourceTypesDiagnosticsArray.Logs -eq $true) {
$resourceDiagnosticscapable = $true
}
else {
$resourceDiagnosticscapable = $false
}
$null = $resourceTypesSummarizedArray.Add([PSCustomObject]@{
ResourceType = $resourceTypeUnique
ResourceCount = $resourcesTypeCountTotal
DiagnosticsCapable = $resourceDiagnosticscapable
Metrics = $dataFromResourceTypesDiagnosticsArray.Metrics
Logs = $dataFromResourceTypesDiagnosticsArray.Logs
LogCategories = ($dataFromResourceTypesDiagnosticsArray.LogCategories -join "$CsvDelimiterOpposite ")
})
}
$subscriptionResourceTypesDiagnosticsCapableMetricsCount = ($resourceTypesSummarizedArray.where( { $_.Metrics -eq $true } )).count
$subscriptionResourceTypesDiagnosticsCapableLogsCount = ($resourceTypesSummarizedArray.where( { $_.Logs -eq $true } )).count
$subscriptionResourceTypesDiagnosticsCapableMetricsLogsCount = ($resourceTypesSummarizedArray.where( { $_.Metrics -eq $true -or $_.Logs -eq $true } )).count
if ($resourcesAllChildSubscriptionResourceTypeCount -gt 0) {
$tfCount = $resourcesAllChildSubscriptionResourceTypeCount
$htmlTableId = "ScopeInsights_resourcesDiagnosticsCapable_$($mgchild -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$subscriptionResourceTypesDiagnosticsCapableMetricsLogsCount/$resourcesAllChildSubscriptionResourceTypeCount ResourceTypes (1st party) Diagnostics capable ($subscriptionResourceTypesDiagnosticsCapableMetricsCount Metrics, $subscriptionResourceTypesDiagnosticsCapableLogsCount Logs) (all Subscriptions below this scope)</span></button>
<div class="content contentSIMG">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">ResourceType</th>
<th>Resource Count</th>
<th>Diagnostics capable</th>
<th>Metrics</th>
<th>Logs</th>
<th>LogCategories</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsDiagnosticsCapable = $null
$htmlScopeInsightsDiagnosticsCapable = foreach ($resourceSubscriptionResourceType in $resourceTypesSummarizedArray | Sort-Object @{Expression = { $_.ResourceType } }) {
@"
<tr>
<td>$($resourceSubscriptionResourceType.ResourceType)</td>
<td>$($resourceSubscriptionResourceType.ResourceCount)</td>
<td>$($resourceSubscriptionResourceType.DiagnosticsCapable)</td>
<td>$($resourceSubscriptionResourceType.Metrics)</td>
<td>$($resourceSubscriptionResourceType.Logs)</td>
<td>$($resourceSubscriptionResourceType.LogCategories)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsDiagnosticsCapable)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_2: 'select',
col_3: 'select',
col_4: 'select',
col_types: [
'caseinsensitivestring',
'number',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $resourcesAllChildSubscriptionResourceTypeCount ResourceTypes (1st party) Diagnostics capable (all Subscriptions below this scope)
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
if ($mgOrSub -eq 'sub') {
$resourceTypesUnique = ($resourcesSubscription | Select-Object type -Unique).type
$resourceTypesSummarizedArray = [System.Collections.ArrayList]@()
foreach ($resourceTypeUnique in $resourceTypesUnique) {
$resourcesTypeCountTotal = 0
($resourcesSubscription.where( { $_.type -eq $resourceTypeUnique } )).count_ | ForEach-Object { $resourcesTypeCountTotal += $_ }
$dataFromResourceTypesDiagnosticsArray = $resourceTypesDiagnosticsArray.where( { $_.ResourceType -eq $resourceTypeUnique } )
if ($dataFromResourceTypesDiagnosticsArray.Metrics -eq $true -or $dataFromResourceTypesDiagnosticsArray.Logs -eq $true) {
$resourceDiagnosticscapable = $true
}
else {
$resourceDiagnosticscapable = $false
}
$null = $resourceTypesSummarizedArray.Add([PSCustomObject]@{
ResourceType = $resourceTypeUnique
ResourceCount = $resourcesTypeCountTotal
DiagnosticsCapable = $resourceDiagnosticscapable
Metrics = $dataFromResourceTypesDiagnosticsArray.Metrics
Logs = $dataFromResourceTypesDiagnosticsArray.Logs
LogCategories = ($dataFromResourceTypesDiagnosticsArray.LogCategories -join "$CsvDelimiterOpposite ")
})
}
$subscriptionResourceTypesDiagnosticsCapableMetricsCount = ($resourceTypesSummarizedArray.where( { $_.Metrics -eq $true } )).count
$subscriptionResourceTypesDiagnosticsCapableLogsCount = ($resourceTypesSummarizedArray.where( { $_.Logs -eq $true } )).count
$subscriptionResourceTypesDiagnosticsCapableMetricsLogsCount = ($resourceTypesSummarizedArray.where( { $_.Metrics -eq $true -or $_.Logs -eq $true } )).count
if ($resourcesSubscriptionResourceTypeCount -gt 0) {
$tfCount = $resourcesSubscriptionResourceTypeCount
$htmlTableId = "ScopeInsights_resourcesDiagnosticsCapable_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$subscriptionResourceTypesDiagnosticsCapableMetricsLogsCount/$resourcesSubscriptionResourceTypeCount ResourceTypes (1st party) Diagnostics capable ($subscriptionResourceTypesDiagnosticsCapableMetricsCount Metrics, $subscriptionResourceTypesDiagnosticsCapableLogsCount Logs)</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">ResourceType</th>
<th>Resource Count</th>
<th>Diagnostics capable</th>
<th>Metrics</th>
<th>Logs</th>
<th>LogCategories</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsDiagnosticsCapable = $null
$htmlScopeInsightsDiagnosticsCapable = foreach ($resourceSubscriptionResourceType in $resourceTypesSummarizedArray | Sort-Object @{Expression = { $_.ResourceType } }) {
@"
<tr>
<td>$($resourceSubscriptionResourceType.ResourceType)</td>
<td>$($resourceSubscriptionResourceType.ResourceCount)</td>
<td>$($resourceSubscriptionResourceType.DiagnosticsCapable)</td>
<td>$($resourceSubscriptionResourceType.Metrics)</td>
<td>$($resourceSubscriptionResourceType.Logs)</td>
<td>$($resourceSubscriptionResourceType.LogCategories)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsDiagnosticsCapable)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_2: 'select',
col_3: 'select',
col_4: 'select',
col_types: [
'caseinsensitivestring',
'number',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $resourcesSubscriptionResourceTypeCount ResourceTypes (1st party) Diagnostics capable
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
#endregion ScopeInsightsDiagnosticsCapable
}
#ScopeInsightsUserAssignedIdentities4Resources
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
if ($mgOrSub -eq 'sub') {
#region ScopeInsightsUserAssignedIdentities4Resources
if ($arrayUserAssignedIdentities4ResourcesSubscriptionCount -gt 0) {
$tfCount = $arrayUserAssignedIdentities4ResourcesSubscriptionCount
$htmlTableId = "ScopeInsights_UserAssignedIdentities4Resources_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-user-circle-o" aria-hidden="true"></i> <span class="valignMiddle">UserAssigned Managed Identities assigned to Resources / vice versa</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">Managed identity 'user-assigned' vs 'system-assigned'</span> <a class="externallink" href="https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview#managed-identity-types" target="_blank" rel="noopener">learn <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>MI Name</th>
<th>MI MgPath</th>
<th>MI Subscription Name</th>
<th>MI Subscription Id</th>
<th>MI ResourceGroup</th>
<th>MI ResourceId</th>
<th>MI AAD SP objectId</th>
<th>MI AAD SP applicationId</th>
<th>MI count Res assignments</th>
<th>MI used cross subscription</th>
<th class="uamiresaltbgc">Res Name</th>
<th class="uamiresaltbgc">Res Type</th>
<th class="uamiresaltbgc">Res MgPath</th>
<th class="uamiresaltbgc">Res Subscription Name</th>
<th class="uamiresaltbgc">Res Subscription Id</th>
<th class="uamiresaltbgc">Res ResourceGroup</th>
<th class="uamiresaltbgc">Res Id</th>
<th class="uamiresaltbgc">Res count assigned MIs</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsUserAssignedIdentities4Resource = $null
$htmlScopeInsightsUserAssignedIdentities4Resource = foreach ($miResEntry in $arrayUserAssignedIdentities4ResourcesSubscription | Sort-Object -Property miResourceId, resourceId) {
@"
<tr>
<td>$($miResEntry.miResourceName)</td>
<td class="breakwordall">$($miResEntry.miMgPath)</td>
<td>$($miResEntry.miSubscriptionName)</td>
<td>$($miResEntry.miSubscriptionId)</td>
<td>$($miResEntry.miResourceGroupName)</td>
<td class="breakwordall">$($miResEntry.miResourceId)</td>
<td>$($miResEntry.miPrincipalId)</td>
<td>$($miResEntry.miClientId)</td>
<td>$($htUserAssignedIdentitiesAssignedResources.($miResEntry.miPrincipalId).ResourcesCount)</td>
<td>$($miResEntry.miCrossSubscription)</td>
<td>$($miResEntry.resourceName)</td>
<td class="breakwordall">$($miResEntry.resourceType)</td>
<td>$($miResEntry.resourceMgPath)</td>
<td>$($miResEntry.resourceSubscriptionName)</td>
<td>$($miResEntry.resourceSubscriptionId)</td>
<td>$($miResEntry.resourceResourceGroupName)</td>
<td class="breakwordall">$($miResEntry.resourceId)</td>
<td>$($htResourcesAssignedUserAssignedIdentities.(($miResEntry.resourceId).tolower()).UserAssignedIdentitiesCount)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsUserAssignedIdentities4Resource)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_9: 'select',
col_11: 'select',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'number',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'number'
],
extensions: [{ name: 'colsVisibility', text: 'Columns: ', enable_tick_all: true },{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No UserAssigned Managed Identities assigned to Resources / vice versa - at all
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsUserAssignedIdentities4Resources
}
}
#ScopeInsightsPSRule
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
if ($azAPICallConf['htParameters'].DoPSRule -eq $true) {
#region ScopeInsightsPSRule
if ($mgOrSub -eq 'mg') {
$allPSRuleResultsUnderThisMg = [system.collections.ArrayList]@()
foreach ($mg in $grpPSRuleManagementGroups) {
$mgNameIdHlper = $mg.name -replace '.*/'
if ($htManagementGroupsMgPath.($mgNameIdHlper).path -contains $mgchild) {
$allPSRuleResultsUnderThisMg.AddRange($mg.Group)
}
}
$grpThisManagementGroup = $allPSRuleResultsUnderThisMg | Group-Object -Property resourceType, pillar, category, severity, rule, result
if ($grpThisManagementGroup) {
$grpThisManagementGroupCount = $grpThisManagementGroup.Count
$tfCount = $grpThisManagementGroupCount
$htmlTableId = "ScopeInsights_PSRule_$($mgchild -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-check-square-o" aria-hidden="true" style="color: #0078df"></i> <span class="valignMiddle">$grpThisManagementGroupCount 'PSRule for Azure' results</span></button>
<div class="content contentSIMG">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">Learn about</span> <a class="externallink" href="https://azure.github.io/PSRule.Rules.Azure" target="_blank" rel="noopener">PSRule for Azure <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Resource Type</th>
<th>Resource Count</th>
<th>Subscription Count</th>
<th>Pillar</th>
<th>Category</th>
<th>Severity</th>
<th>Rule</th>
<th>Recommendation</th>
<th>lnk</th>
<th>State</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsPSRuleMG = $null
$htmlScopeInsightsPSRuleMG = foreach ($result in $grpThisManagementGroup) {
$resultNameSplit = $result.Name.split(', ')
@"
<tr>
<td>$($resultNameSplit[0])</td>
<td>$($result.Group.Count)</td>
<td>$(($result.Group.subscriptionId | Sort-Object -Unique).Count)</td>
<td>$($resultNameSplit[1])</td>
<td>$($resultNameSplit[2])</td>
<td>$($resultNameSplit[3])</td>
<td>$(($result.Group[0].rule))</td>
<td>$(($result.Group[0].recommendation))</td>
<td><a href=`"$(($result.Group[0].link))`" target=`"_blank`"><i class="fa fa-external-link" aria-hidden="true"></i></a></td>
<td>$($resultNameSplit[5])</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsPSRuleMG)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_3: 'select',
col_4: 'select',
col_5: 'select',
col_9: 'select',
col_types: [
'caseinsensitivestring',
'number',
'number',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No PSRule for Azure results
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
}
if ($mgOrSub -eq 'sub') {
$grpThisSubscription = $grpPSRuleSubscriptions.where({ $_.Name -eq $subscriptionId })
$grpThisSubscriptionGrouped = $grpThisSubscription.Group | Group-Object -Property resourceType, pillar, category, severity, rule, result
if ($grpThisSubscriptionGrouped) {
$grpThisSubscriptionGroupedCount = $grpThisSubscriptionGrouped.Count
$tfCount = $grpThisSubscriptionGroupedCount
$htmlTableId = "ScopeInsights_PSRule_$($subscriptionId -replace '-','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">
<i class="fa fa-check-square-o" aria-hidden="true"></i> <span class="valignMiddle">$grpThisSubscriptionGroupedCount PSRule for Azure results</span></button>
<div class="content contentSISub">
<i class="fa fa-lightbulb-o" aria-hidden="true"></i> <span class="info">Learn about</span> <a class="externallink" href="https://azure.github.io/PSRule.Rules.Azure" target="_blank" rel="noopener">PSRule for Azure <i class="fa fa-external-link" aria-hidden="true"></i></a><br>
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Resource Type</th>
<th>Resource Count</th>
<th>Pillar</th>
<th>Category</th>
<th>Severity</th>
<th>Rule</th>
<th>Recommendation</th>
<th>lnk</th>
<th>State</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsPSRuleSub = $null
$htmlScopeInsightsPSRuleSub = foreach ($result in $grpThisSubscriptionGrouped) {
$resultNameSplit = $result.Name.split(', ')
@"
<tr>
<td>$($resultNameSplit[0])</td>
<td>$($result.Group.Count)</td>
<td>$($resultNameSplit[1])</td>
<td>$($resultNameSplit[2])</td>
<td>$($resultNameSplit[3])</td>
<td>$(($result.Group[0].rule))</td>
<td>$(($result.Group[0].recommendation))</td>
<td><a href=`"$(($result.Group[0].link))`" target=`"_blank`"><i class="fa fa-external-link" aria-hidden="true"></i></a></td>
<td>$($resultNameSplit[5])</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsPSRuleSub)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_2: 'select',
col_3: 'select',
col_4: 'select',
col_8: 'select',
col_types: [
'caseinsensitivestring',
'number',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
</div>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No PSRule results
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
}
#endregion ScopeInsightsPSRule
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-check-square-o" aria-hidden="true"></i> PSRule for Azure - <span class="info">integration paused - <a class="externallink" href="https://azure.github.io/PSRule.Rules.Azure/integrations" target="_blank" rel="noopener">PSRule for Azure <i class="fa fa-external-link" aria-hidden="true"></i></a>
'@)
}
}
#PolicyAssignments
#region ScopeInsightsPolicyAssignments
if ($mgOrSub -eq 'mg') {
$SIDivContentClass = 'contentSIMG'
$htmlTableIdentifier = $mgChild
$policiesAssigned = [System.Collections.ArrayList]@()
$policiesCount = 0
$policiesCountBuiltin = 0
$policiesCountCustom = 0
$policiesAssignedAtScope = 0
$policiesInherited = 0
foreach ($policyAssignment in $arrayPolicyAssignmentsEnrichedForThisManagementGroupVariantPolicy) {
if ([String]::IsNullOrEmpty($policyAssignment.subscriptionId)) {
$null = $policiesAssigned.Add($policyAssignment)
$policiesCount++
if ($policyAssignment.PolicyType -eq 'BuiltIn') {
$policiesCountBuiltin++
}
if ($policyAssignment.PolicyType -eq 'Custom') {
$policiesCountCustom++
}
if ($policyAssignment.Inheritance -like 'this*') {
$policiesAssignedAtScope++
}
if ($policyAssignment.Inheritance -notlike 'this*') {
$policiesInherited++
}
}
}
}
if ($mgOrSub -eq 'sub') {
$SIDivContentClass = 'contentSISub'
$htmlTableIdentifier = $subscriptionId
$policiesAssigned = [System.Collections.ArrayList]@()
$policiesCount = 0
$policiesCountBuiltin = 0
$policiesCountCustom = 0
$policiesAssignedAtScope = 0
$policiesInherited = 0
foreach ($policyAssignment in $arrayPolicyAssignmentsEnrichedForThisSubscriptionVariantPolicy) {
$null = $policiesAssigned.Add($policyAssignment)
$policiesCount++
if ($policyAssignment.PolicyType -eq 'BuiltIn') {
$policiesCountBuiltin++
}
if ($policyAssignment.PolicyType -eq 'Custom') {
$policiesCountCustom++
}
if ($policyAssignment.Inheritance -like 'this*') {
$policiesAssignedAtScope++
}
if ($policyAssignment.Inheritance -notlike 'this*') {
$policiesInherited++
}
}
}
if (($policiesAssigned).count -gt 0) {
$tfCount = ($policiesAssigned).count
$htmlTableId = "ScopeInsights_PolicyAssignments_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
$noteOrNot = ''
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$policiesCount Policy assignments ($policiesAssignedAtScope at scope, $policiesInherited inherited) (Builtin: $policiesCountBuiltin | Custom: $policiesCountCustom)</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a><br>
<span class="hintTableSize">*Depending on the number of rows and your computer´s performance the table may respond with delay, download the csv for better filtering experience</span>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Inheritance</th>
<th>ScopeExcluded</th>
<th>Exemption applies</th>
<th>Policy DisplayName</th>
<th>PolicyId</th>
<th>Type</th>
<th>Category</th>
<th>ALZ</th>
<th>Effect</th>
<th>Parameters</th>
<th>Enforcement</th>
<th>NonCompliance Message</th>
"@)
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
[void]$htmlScopeInsights.AppendLine(@'
<th>Policies NonCmplnt</th>
<th>Policies Compliant</th>
<th>Resources NonCmplnt</th>
<th>Resources Compliant</th>
<th>Resources Conflicting</th>
'@)
}
[void]$htmlScopeInsights.AppendLine(@"
<th>Role/Assignment $noteOrNot</th>
<th>Managed Identity</th>
<th>Assignment DisplayName</th>
<th>AssignmentId</th>
<th>AssignedBy</th>
<th>CreatedOn</th>
<th>CreatedBy</th>
<th>UpdatedOn</th>
<th>UpdatedBy</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsPolicyAssignments = $null
$htmlScopeInsightsPolicyAssignments = foreach ($policyAssignment in $policiesAssigned | Sort-Object @{Expression = { $_.Level } }, @{Expression = { $_.MgName } }, @{Expression = { $_.MgId } }, @{Expression = { $_.SubscriptionName } }, @{Expression = { $_.SubscriptionId } }, @{Expression = { $_.PolicyAssignmentId } }) {
if ($policyAssignment.PolicyType -eq 'Custom') {
$policyName = ($policyAssignment.PolicyName -replace '<', '<' -replace '>', '>')
}
else {
$policyName = $policyAssignment.PolicyName
}
@"
<tr>
<td>$($policyAssignment.Inheritance)</td>
<td>$($policyAssignment.ExcludedScope)</td>
<td>$($policyAssignment.ExemptionScope)</td>
<td class="breakwordall">$($policyName)</td>
<td class="breakwordall">$($policyAssignment.PolicyId)</td>
<td>$($policyAssignment.PolicyType)</td>
<td>$($policyAssignment.PolicyCategory -replace '<', '<' -replace '>', '>')</td>
<td>$($policyAssignment.PolicyIsALZ)</td>
<td>$($policyAssignment.Effect)</td>
<td>$($policyAssignment.PolicyAssignmentParameters)</td>
<td>$($policyAssignment.PolicyAssignmentEnforcementMode)</td>
<td>$($policyAssignment.PolicyAssignmentNonComplianceMessages)</td>
"@
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
@"
<td>$($policyAssignment.NonCompliantPolicies)</td>
<td>$($policyAssignment.CompliantPolicies)</td>
<td>$($policyAssignment.NonCompliantResources)</td>
<td>$($policyAssignment.CompliantResources)</td>
<td>$($policyAssignment.ConflictingResources)</td>
"@
}
@"
<td class="breakwordall">$($policyAssignment.RelatedRoleAssignments)</td>
<td>$($policyAssignment.PolicyAssignmentMI)</td>
<td class="breakwordall">$($policyAssignment.PolicyAssignmentDisplayName -replace '<', '<' -replace '>', '>')</td>
<td class="breakwordall">$($policyAssignment.PolicyAssignmentId -replace '<', '<' -replace '>', '>')</td>
<td>$($policyAssignment.AssignedBy)</td>
<td>$($policyAssignment.CreatedOn)</td>
<td>$($policyAssignment.CreatedBy)</td>
<td>$($policyAssignment.UpdatedOn)</td>
<td>$($policyAssignment.UpdatedBy)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsPolicyAssignments)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_1: 'select',
col_2: 'select',
col_5: 'select',
col_7: 'select',
col_8: 'select',
col_10: 'select',
locale: 'en-US',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'@)
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
[void]$htmlScopeInsights.AppendLine(@'
'number',
'number',
'number',
'number',
'number',
'@)
}
[void]$htmlScopeInsights.AppendLine(@"
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'date',
'caseinsensitivestring',
'date',
'caseinsensitivestring'
],
watermark: ['try: thisScope'],
extensions: [{ name: 'colsVisibility', text: 'Columns: ', enable_tick_all: true },{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $(($policiesAssigned).count) Policy assignments
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsPolicyAssignments
#PolicySetAssignments
#region ScopeInsightsPolicySetAssignments
if ($mgOrSub -eq 'mg') {
$SIDivContentClass = 'contentSIMG'
$htmlTableIdentifier = $mgChild
$policySetsAssigned = [System.Collections.ArrayList]@()
$policySetsCount = 0
$policySetsCountBuiltin = 0
$policySetsCountCustom = 0
$policySetsAssignedAtScope = 0
$policySetsInherited = 0
foreach ($policySetAssignment in $arrayPolicyAssignmentsEnrichedForThisManagementGroupVariantPolicySet) {
if ([String]::IsNullOrEmpty($policySetAssignment.subscriptionId)) {
$null = $policySetsAssigned.Add($policySetAssignment)
$policySetsCount++
if ($policySetAssignment.PolicyType -eq 'BuiltIn') {
$policySetsCountBuiltin++
}
if ($policySetAssignment.PolicyType -eq 'Custom') {
$policySetsCountCustom++
}
if ($policySetAssignment.Inheritance -like 'this*') {
$policySetsAssignedAtScope++
}
if ($policySetAssignment.Inheritance -notlike 'this*') {
$policySetsInherited++
}
}
}
}
if ($mgOrSub -eq 'sub') {
$SIDivContentClass = 'contentSISub'
$htmlTableIdentifier = $subscriptionId
$policySetsAssigned = [System.Collections.ArrayList]@()
$policySetsCount = 0
$policySetsCountBuiltin = 0
$policySetsCountCustom = 0
$policySetsAssignedAtScope = 0
$policySetsInherited = 0
foreach ($policySetAssignment in $arrayPolicyAssignmentsEnrichedForThisSubscriptionVariantPolicySet) {
$null = $policySetsAssigned.Add($policySetAssignment)
$policySetsCount++
if ($policySetAssignment.PolicyType -eq 'BuiltIn') {
$policySetsCountBuiltin++
}
if ($policySetAssignment.PolicyType -eq 'Custom') {
$policySetsCountCustom++
}
if ($policySetAssignment.Inheritance -like 'this*') {
$policySetsAssignedAtScope++
}
if ($policySetAssignment.Inheritance -notlike 'this*') {
$policySetsInherited++
}
}
}
if (($policySetsAssigned).count -gt 0) {
$tfCount = ($policiesAssigned).count
$htmlTableId = "ScopeInsights_PolicySetAssignments_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
$noteOrNot = ''
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$policySetsCount PolicySet assignments ($policySetsAssignedAtScope at scope, $policySetsInherited inherited) (Builtin: $policySetsCountBuiltin | Custom: $policySetsCountCustom)</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Inheritance</th>
<th>ScopeExcluded</th>
<th>PolicySet DisplayName</th>
<th>PolicySetId</th>
<th>Type</th>
<th>Category</th>
<th>ALZ</th>
<th>Parameters</th>
<th>Enforcement</th>
<th>NonCompliance Message</th>
"@)
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
[void]$htmlScopeInsights.AppendLine(@'
<th>Policies NonCmplnt</th>
<th>Policies Compliant</th>
<th>Resources NonCmplnt</th>
<th>Resources Compliant</th>
<th>Resources Conflicting</th>
'@)
}
[void]$htmlScopeInsights.AppendLine(@"
<th>Role/Assignment $noteOrNot</th>
<th>Managed Identity</th>
<th>Assignment DisplayName</th>
<th>AssignmentId</th>
<th>AssignedBy</th>
<th>CreatedOn</th>
<th>CreatedBy</th>
<th>UpdatedOn</th>
<th>UpdatedBy</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsPolicySetAssignments = $null
$htmlScopeInsightsPolicySetAssignments = foreach ($policyAssignment in $policySetsAssigned | Sort-Object -Property Level, PolicyAssignmentId) {
if ($policyAssignment.PolicyType -eq 'Custom') {
$policyName = ($policyAssignment.PolicyName -replace '<', '<' -replace '>', '>')
}
else {
$policyName = $policyAssignment.PolicyName
}
@"
<tr>
<td>$($policyAssignment.Inheritance)</td>
<td>$($policyAssignment.ExcludedScope)</td>
<td class="breakwordall">$($policyName)</td>
<td class="breakwordall">$($policyAssignment.PolicyId)</td>
<td>$($policyAssignment.PolicyType)</td>
<td>$($policyAssignment.PolicyCategory -replace '<', '<' -replace '>', '>')</td>
<td>$($policyAssignment.PolicyIsALZ)</td>
<td>$($policyAssignment.PolicyAssignmentParameters)</td>
<td>$($policyAssignment.PolicyAssignmentEnforcementMode)</td>
<td>$($policyAssignment.PolicyAssignmentNonComplianceMessages)</td>
"@
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
@"
<td>$($policyAssignment.NonCompliantPolicies)</td>
<td>$($policyAssignment.CompliantPolicies)</td>
<td>$($policyAssignment.NonCompliantResources)</td>
<td>$($policyAssignment.CompliantResources)</td>
<td>$($policyAssignment.ConflictingResources)</td>
"@
}
@"
<td class="breakwordall">$($policyAssignment.RelatedRoleAssignments)</td>
<td>$($policyAssignment.PolicyAssignmentMI)</td>
<td class="breakwordall">$($policyAssignment.PolicyAssignmentDisplayName -replace '<', '<' -replace '>', '>')</td>
<td class="breakwordall">$($policyAssignment.PolicyAssignmentId -replace '<', '<' -replace '>', '>')</td>
<td>$($policyAssignment.AssignedBy)</td>
<td>$($policyAssignment.CreatedOn)</td>
<td>$($policyAssignment.CreatedBy)</td>
<td>$($policyAssignment.UpdatedOn)</td>
<td>$($policyAssignment.UpdatedBy)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsPolicySetAssignments)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_1: 'select',
col_4: 'select',
col_6: 'select',
col_8: 'select',
locale: 'en-US',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'@)
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
[void]$htmlScopeInsights.AppendLine(@'
'number',
'number',
'number',
'number',
'number',
'@)
}
[void]$htmlScopeInsights.AppendLine(@"
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'date',
'caseinsensitivestring',
'date',
'caseinsensitivestring'
],
watermark: ['try: thisScope'],
extensions: [{ name: 'colsVisibility', text: 'Columns: ', enable_tick_all: true },{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $(($policySetsAssigned).count) PolicySet assignments
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><!--y--><td class="detailstd"><!--y-->
'@)
#endregion ScopeInsightsPolicySetAssignments
#PolicyAssignmentsLimit (Policy+PolicySet)
#region ScopeInsightsPolicyAssignmentsLimit
if ($mgOrSub -eq 'mg') {
$limit = $LimitPOLICYPolicyAssignmentsManagementGroup
}
if ($mgOrSub -eq 'sub') {
$limit = $LimitPOLICYPolicyAssignmentsSubscription
}
if ($policiesAssignedAtScope -eq 0 -and $policySetsAssignedAtScope -eq 0) {
$faimage = "<i class=`"fa fa-ban`" aria-hidden=`"true`"></i>"
[void]$htmlScopeInsights.AppendLine(@"
$faImage Policy Assignment Limit: 0/$limit
"@)
}
else {
if ($mgOrSub -eq 'mg') {
$scopePolicyAssignmentsLimit = $policyPolicyBaseQueryScopeInsights.where( { [String]::IsNullOrEmpty($_.SubscriptionId) -and $_.MgId -eq $mgChild } )
}
if ($mgOrSub -eq 'sub') {
$scopePolicyAssignmentsLimit = $policyPolicyBaseQueryScopeInsights.where( { $_.SubscriptionId -eq $subscriptionId } )
}
if ($scopePolicyAssignmentsLimit.PolicyAndPolicySetAssignmentAtScopeCount -gt (($limit) * $LimitCriticalPercentage / 100)) {
$faImage = "<i class=`"fa fa-exclamation-triangle`" aria-hidden=`"true`"></i>"
}
else {
$faimage = "<i class=`"fa fa-check-circle`" aria-hidden=`"true`"></i>"
}
[void]$htmlScopeInsights.AppendLine(@"
$faImage Policy Assignment Limit: $($scopePolicyAssignmentsLimit.PolicyAndPolicySetAssignmentAtScopeCount)/$($limit)
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsPolicyAssignmentsLimit
#ScopedPolicies
#region ScopeInsightsScopedPolicies
if ($mgOrSub -eq 'mg') {
$SIDivContentClass = 'contentSIMG'
$htmlTableIdentifier = $mgChild
$scopePolicies = $customPoliciesDetailed.where( { $_.PolicyDefinitionId -like "*/providers/Microsoft.Management/managementGroups/$mgChild/*" } )
$scopePoliciesCount = ($scopePolicies).count
}
if ($mgOrSub -eq 'sub') {
$SIDivContentClass = 'contentSISub'
$htmlTableIdentifier = $subscriptionId
$scopePolicies = $customPoliciesDetailed.where( { $_.PolicyDefinitionId -like "*/subscriptions/$subscriptionId/*" } )
$scopePoliciesCount = ($scopePolicies).count
}
if ($scopePoliciesCount -gt 0) {
$tfCount = $scopePoliciesCount
$htmlTableId = "ScopeInsights_ScopedPolicies_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
if ($mgOrSub -eq 'mg') {
$LimitPOLICYPolicyScoped = $LimitPOLICYPolicyDefinitionsScopedManagementGroup
if ($scopePoliciesCount -gt (($LimitPOLICYPolicyScoped * $LimitCriticalPercentage) / 100)) {
$faIcon = "<i class=`"fa fa-exclamation-triangle`" aria-hidden=`"true`"></i>"
}
else {
$faIcon = "<i class=`"fa fa-check-circle blue`" aria-hidden=`"true`"></i>"
}
}
if ($mgOrSub -eq 'sub') {
$LimitPOLICYPolicyScoped = $LimitPOLICYPolicyDefinitionsScopedSubscription
if ($scopePoliciesCount -gt (($LimitPOLICYPolicyScoped * $LimitCriticalPercentage) / 100)) {
$faIcon = "<i class=`"fa fa-exclamation-triangle`" aria-hidden=`"true`"></i>"
}
else {
$faIcon = "<i class=`"fa fa-check-circle blue`" aria-hidden=`"true`"></i>"
}
}
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">$faIcon <span class="valignMiddle">$scopePoliciesCount Custom Policy definitions scoped | Limit: ($scopePoliciesCount/$LimitPOLICYPolicyScoped)</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">Policy DisplayName</th>
<th>PolicyId</th>
<th>Category</th>
<th>ALZ</th>
<th>Policy effect</th>
<th>Role definitions</th>
<th>Unique assignments</th>
<th>Used in PolicySets</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsScopedPolicies = $null
$htmlScopeInsightsScopedPolicies = foreach ($custompolicy in $scopePolicies | Sort-Object @{Expression = { $_.PolicyDisplayName } }, @{Expression = { $_.PolicyDefinitionId } }) {
if ($custompolicy.UsedInPolicySetsCount -gt 0) {
$customPolicyUsedInPolicySets = "$($customPolicy.UsedInPolicySetsCount) ($($customPolicy.UsedInPolicySets))"
}
else {
$customPolicyUsedInPolicySets = $($customPolicy.UsedInPolicySetsCount)
}
@"
<tr>
<td>$($customPolicy.PolicyDisplayName -replace '<', '<' -replace '>', '>')</td>
<td class="breakwordall">$($customPolicy.PolicyDefinitionId -replace '<', '<' -replace '>', '>')</td>
<td>$($customPolicy.PolicyCategory -replace '<', '<' -replace '>', '>')</td>
<td>$($customPolicy.ALZ)</td>
<td>$($customPolicy.PolicyEffect)</td>
<td>$($customPolicy.RoleDefinitions)</td>
<td class="breakwordall">$($customPolicy.UniqueAssignments -replace '<', '<' -replace '>', '>')</td>
<td class="breakwordall">$($customPolicyUsedInPolicySets)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsScopedPolicies)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_3: 'select',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $scopePoliciesCount Custom Policy definitions scoped
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsScopedPolicies
#ScopedPolicySets
#region ScopeInsightsScopedPolicySets
if ($mgOrSub -eq 'mg') {
$SIDivContentClass = 'contentSIMG'
$htmlTableIdentifier = $mgChild
$scopePolicySets = $customPolicySetsDetailed.where( { $_.PolicySetDefinitionId -like "*/providers/Microsoft.Management/managementGroups/$mgChild/*" } )
$scopePolicySetsCount = ($scopePolicySets).count
}
if ($mgOrSub -eq 'sub') {
$SIDivContentClass = 'contentSISub'
$htmlTableIdentifier = $subscriptionId
$scopePolicySets = $customPolicySetsDetailed.where( { $_.PolicySetDefinitionId -like "*/subscriptions/$subscriptionId/*" } )
$scopePolicySetsCount = ($scopePolicySets).count
}
if ($scopePolicySetsCount -gt 0) {
$tfCount = $scopePolicySetsCount
$htmlTableId = "ScopeInsights_ScopedPolicySets_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
if ($mgOrSub -eq 'mg') {
$LimitPOLICYPolicySetScoped = $LimitPOLICYPolicySetDefinitionsScopedManagementGroup
if ($scopePolicySetsCount -gt (($LimitPOLICYPolicySetScoped * $LimitCriticalPercentage) / 100)) {
$faIcon = "<i class=`"fa fa-exclamation-triangle`" aria-hidden=`"true`"></i>"
}
else {
$faIcon = "<i class=`"fa fa-check-circle blue`" aria-hidden=`"true`"></i>"
}
}
if ($mgOrSub -eq 'sub') {
$LimitPOLICYPolicySetScoped = $LimitPOLICYPolicySetDefinitionsScopedSubscription
if ($scopePolicySetsCount -gt (($LimitPOLICYPolicySetScoped * $LimitCriticalPercentage) / 100)) {
$faIcon = "<i class=`"fa fa-exclamation-triangle`" aria-hidden=`"true`"></i>"
}
else {
$faIcon = "<i class=`"fa fa-check-circle blue`" aria-hidden=`"true`"></i>"
}
}
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible">$faIcon <span class="valignMiddle">$scopePolicySetsCount Custom PolicySet definitions scoped | Limit: ($scopePolicySetsCount/$LimitPOLICYPolicySetScoped)</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">PolicySet DisplayName</th>
<th>PolicySetId</th>
<th>Category</th>
<th>ALZ</th>
<th>Unique assignments</th>
<th>Policies Used</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsScopedPolicySets = $null
$htmlScopeInsightsScopedPolicySets = foreach ($custompolicySet in $scopePolicySets | Sort-Object @{Expression = { $_.PolicySetDisplayName } }, @{Expression = { $_.PolicySetDefinitionId } }) {
@"
<tr>
<td>$($custompolicySet.PolicySetDisplayName -replace '<', '<' -replace '>', '>')</td>
<td>$($custompolicySet.PolicySetDefinitionId -replace '<', '<' -replace '>', '>')</td>
<td>$($custompolicySet.PolicySetCategory -replace '<', '<' -replace '>', '>')</td>
<td>$($custompolicySet.ALZ)</td>
<td>$($custompolicySet.UniqueAssignments -replace '<', '<' -replace '>', '>')</td>
<td>$($custompolicySet.PoliciesUsed)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsScopedPolicySets)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_3: 'select',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $scopePolicySetsCount Custom PolicySet definitions scoped
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsScopedPolicySets
#BlueprintAssignments
#region ScopeInsightsBlueprintAssignments
if ($mgOrSub -eq 'sub') {
if ($blueprintsAssignedCount -gt 0) {
if ($mgOrSub -eq 'mg') {
$htmlTableIdentifier = $mgChild
}
if ($mgOrSub -eq 'sub') {
$htmlTableIdentifier = $subscriptionId
}
$htmlTableId = "ScopeInsights_BlueprintAssignment_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$blueprintsAssignedCount Blueprints assigned</span></button>
<div class="content contentSISub">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">Blueprint Name</th>
<th>Blueprint DisplayName</th>
<th>Blueprint Description</th>
<th>BlueprintId</th>
<th>Blueprint Version</th>
<th>Blueprint AssignmentId</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsBlueprintAssignments = $null
$htmlScopeInsightsBlueprintAssignments = foreach ($blueprintAssigned in $blueprintsAssigned) {
@"
<tr>
<td>$($blueprintAssigned.BlueprintName -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintAssigned.BlueprintDisplayName -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintAssigned.BlueprintDescription -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintAssigned.BlueprintId -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintAssigned.BlueprintAssignmentVersion -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintAssigned.BlueprintAssignmentId -replace '<', '<' -replace '>', '>')</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsBlueprintAssignments)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $blueprintsAssignedCount Blueprints assigned
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
}
#endregion ScopeInsightsBlueprintAssignments
#BlueprintsScoped
#region ScopeInsightsBlueprintsScoped
if ($blueprintsScopedCount -gt 0) {
$tfCount = $blueprintsScopedCount
if ($mgOrSub -eq 'mg') {
$SIDivContentClass = 'contentSIMG'
$htmlTableIdentifier = $mgChild
}
if ($mgOrSub -eq 'sub') {
$SIDivContentClass = 'contentSISub'
$htmlTableIdentifier = $subscriptionId
}
$htmlTableId = "ScopeInsights_BlueprintScoped_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$blueprintsScopedCount Blueprints scoped</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th class="widthCustom">Blueprint Name</th>
<th>Blueprint DisplayName</th>
<th>Blueprint Description</th>
<th>BlueprintId</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsBlueprintsScoped = $null
$htmlScopeInsightsBlueprintsScoped = foreach ($blueprintScoped in $blueprintsScoped) {
@"
<tr>
<td>$($blueprintScoped.BlueprintName -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintScoped.BlueprintDisplayName -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintScoped.BlueprintDescription -replace '<', '<' -replace '>', '>')</td>
<td>$($blueprintScoped.BlueprintId -replace '<', '<' -replace '>', '>')</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsBlueprintsScoped)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $blueprintsScopedCount Blueprints scoped
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsBlueprintsScoped
if ($mgOrSub -eq 'sub') {
#region ScopeInsightsClassicAdministrators
if ($htClassicAdministrators.($subscriptionId).ClassicAdministrators.Count -gt 0) {
$tfCount = $htClassicAdministrators.($subscriptionId).ClassicAdministrators.Count
$htmlTableId = "ScopeInsights_ClassicAdministrators_$($subscriptionId -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$tfCount Classic Administrators</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Role</th>
<th>Identity</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsClassicAdministrators = $null
$htmlScopeInsightsClassicAdministrators = foreach ($classicAdministrator in $htClassicAdministrators.($subscriptionId).ClassicAdministrators | Sort-Object -Property Role, Identity) {
@"
<tr>
<td>$($classicAdministrator.Role)</td>
<td>$($classicAdministrator.Identity)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsClassicAdministrators)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
col_types: [
'caseinsensitivestring',
'caseinsensitivestring'
],
extensions: [{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@'
<i class="fa fa-ban" aria-hidden="true"></i> No Classic Administrators
'@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr>
<tr><td class="detailstd">
'@)
#endregion ScopeInsightsClassicAdministrators
}
#RoleAssignments
#region ScopeInsightsRoleAssignments
if ($mgOrSub -eq 'mg') {
$SIDivContentClass = 'contentSIMG'
$htmlTableIdentifier = $mgChild
$LimitRoleAssignmentsScope = $LimitRBACRoleAssignmentsManagementGroup
$rolesAssigned = [System.Collections.ArrayList]@()
$rolesAssignedCount = 0
$rolesAssignedInheritedCount = 0
$rolesAssignedUser = 0
$rolesAssignedGroup = 0
$rolesAssignedServicePrincipal = 0
$rolesAssignedUnknown = 0
$roleAssignmentsRelatedToPolicyCount = 0
$roleSecurityFindingCustomRoleOwner = 0
$roleSecurityFindingOwnerAssignmentSP = 0
$rbacForThisManagementGroup = ($rbacAllGroupedByManagementGroup.where( { $_.name -eq $mgChild } )).group
foreach ($roleAssignment in $rbacForThisManagementGroup) {
if ([String]::IsNullOrEmpty($roleAssignment.subscriptionId)) {
$null = $rolesAssigned.Add($roleAssignment)
$rolesAssignedCount++
if ($roleAssignment.Scope -notlike 'this*') {
$rolesAssignedInheritedCount++
}
if ($roleAssignment.ObjectType -like 'User*') {
$rolesAssignedUser++
}
if ($roleAssignment.ObjectType -eq 'Group') {
$rolesAssignedGroup++
}
if ($roleAssignment.ObjectType -like 'SP*') {
$rolesAssignedServicePrincipal++
}
if ($roleAssignment.ObjectType -eq 'Unknown') {
$rolesAssignedUnknown++
}
if ($roleAssignment.RbacRelatedPolicyAssignment -ne 'none') {
$roleAssignmentsRelatedToPolicyCount++
}
if ($roleAssignment.RoleSecurityCustomRoleOwner -eq 1) {
$roleSecurityFindingCustomRoleOwner++
}
if ($roleAssignment.RoleSecurityOwnerAssignmentSP -eq 1) {
$roleSecurityFindingOwnerAssignmentSP++
}
}
}
}
if ($mgOrSub -eq 'sub') {
$SIDivContentClass = 'contentSISub'
$htmlTableIdentifier = $subscriptionId
$LimitRoleAssignmentsScope = $htSubscriptionsRoleAssignmentLimit.($subscriptionId)
$rolesAssigned = [System.Collections.ArrayList]@()
$rolesAssignedCount = 0
$rolesAssignedInheritedCount = 0
$rolesAssignedUser = 0
$rolesAssignedGroup = 0
$rolesAssignedServicePrincipal = 0
$rolesAssignedUnknown = 0
$roleAssignmentsRelatedToPolicyCount = 0
$roleSecurityFindingCustomRoleOwner = 0
$roleSecurityFindingOwnerAssignmentSP = 0
$rbacForThisSubscription = ($rbacAllGroupedBySubscription.where( { $_.name -eq $subscriptionId } )).group
$rolesAssigned = foreach ($roleAssignment in $rbacForThisSubscription) {
$roleAssignment
$rolesAssignedCount++
if ($roleAssignment.Scope -notlike 'this*') {
$rolesAssignedInheritedCount++
}
if ($roleAssignment.ObjectType -like 'User*') {
$rolesAssignedUser++
}
if ($roleAssignment.ObjectType -eq 'Group') {
$rolesAssignedGroup++
}
if ($roleAssignment.ObjectType -like 'SP*') {
$rolesAssignedServicePrincipal++
}
if ($roleAssignment.ObjectType -eq 'Unknown') {
$rolesAssignedUnknown++
}
if ($roleAssignment.RbacRelatedPolicyAssignment -ne 'none') {
$roleAssignmentsRelatedToPolicyCount++
}
if ($roleAssignment.RoleSecurityCustomRoleOwner -eq 1) {
$roleSecurityFindingCustomRoleOwner++
}
if ($roleAssignment.RoleSecurityOwnerAssignmentSP -eq 1) {
$roleSecurityFindingOwnerAssignmentSP++
}
}
}
$rolesAssignedAtScopeCount = $rolesAssignedCount - $rolesAssignedInheritedCount
if (($rolesAssigned).count -gt 0) {
$tfCount = ($rolesAssigned).count
$htmlTableId = "ScopeInsights_RoleAssignments_$($htmlTableIdentifier -replace '\(','_' -replace '\)','_' -replace '-','_' -replace '\.','_')"
$randomFunctionName = "func_$htmlTableId"
$noteOrNot = ''
[void]$htmlScopeInsights.AppendLine(@"
<button onclick="loadtf$("func_$htmlTableId")()" type="button" class="collapsible"><i class="fa fa-check-circle blue" aria-hidden="true"></i> <span class="valignMiddle">$rolesAssignedCount Role assignments ($rolesAssignedInheritedCount inherited) (User: $rolesAssignedUser | Group: $rolesAssignedGroup | ServicePrincipal: $rolesAssignedServicePrincipal | Orphaned: $rolesAssignedUnknown) ($($roleSecurityFindingCustomRoleOwnerImg)CustomRoleOwner: $roleSecurityFindingCustomRoleOwner, $($RoleSecurityFindingOwnerAssignmentSPImg)OwnerAssignmentSP: $roleSecurityFindingOwnerAssignmentSP) (Policy related: $roleAssignmentsRelatedToPolicyCount) | Limit: ($rolesAssignedAtScopeCount/$LimitRoleAssignmentsScope)</span></button>
<div class="content $SIDivContentClass">
<i class="fa fa-table" aria-hidden="true"></i> Download CSV <a class="externallink" href="#" onclick="download_table_as_csv_semicolon('$htmlTableId');">semicolon</a> | <a class="externallink" href="#" onclick="download_table_as_csv_comma('$htmlTableId');">comma</a><br>
<span class="hintTableSize">*Depending on the number of rows and your computer´s performance the table may respond with delay, download the csv for better filtering experience</span>
<table id="$htmlTableId" class="$cssClass">
<thead>
<tr>
<th>Scope</th>
<th>Role</th>
<th>RoleId</th>
<th>Role Type</th>
<th>Data</th>
<th>Can do Role assignment</th>
<th>Identity Displayname</th>
<th>Identity SignInName</th>
<th>Identity ObjectId</th>
<th>Identity Type</th>
<th>Applicability</th>
<th>Applies through membership <abbr title="Note: the identity might not be a direct member of the group it could also be member of a nested group"><i class="fa fa-question-circle" aria-hidden="true"></i></abbr></th>
<th>Group Details</th>
<th>Role AssignmentId</th>
<th>Related Policy Assignment $noteOrNot</th>
<th>CreatedOn</th>
<th>CreatedBy</th>
</tr>
</thead>
<tbody>
"@)
$htmlScopeInsightsRoleAssignments = $null
$htmlScopeInsightsRoleAssignments = foreach ($roleAssignment in ($rolesAssigned | Sort-Object -Property Level, MgName, MgId, SubscriptionName, SubscriptionId, Scope, Role, RoleId, ObjectId, RoleAssignmentId)) {
@"
<tr>
<td>$($roleAssignment.Scope)</td>
<td>$($roleAssignment.Role)</td>
<td>$($roleAssignment.RoleId)</td>
<td>$($roleAssignment.RoleType)</td>
<td>$($roleAssignment.RoleDataRelated)</td>
<td>$($roleAssignment.RoleCanDoRoleAssignments)</td>
<td class="breakwordall">$($roleAssignment.ObjectDisplayName)</td>
<td class="breakwordall">$($roleAssignment.ObjectSignInName)</td>
<td class="breakwordall">$($roleAssignment.ObjectId)</td>
<td style="width:76px" class="breakwordnone">$($roleAssignment.ObjectType)</td>
<td>$($roleAssignment.AssignmentType)</td>
<td>$($roleAssignment.AssignmentInheritFrom)</td>
<td>$($roleAssignment.GroupMembersCount)</td>
<td class="breakwordall">$($roleAssignment.RoleAssignmentId)</td>
<td class="breakwordall">$($roleAssignment.rbacRelatedPolicyAssignment)</td>
<td>$($roleAssignment.CreatedOn)</td>
<td>$($roleAssignment.CreatedBy)</td>
</tr>
"@
}
[void]$htmlScopeInsights.AppendLine($htmlScopeInsightsRoleAssignments)
[void]$htmlScopeInsights.AppendLine(@"
</tbody>
</table>
</div>
<script>
function loadtf$("func_$htmlTableId")() { if (window.helpertfConfig4$htmlTableId !== 1) {
window.helpertfConfig4$htmlTableId =1;
var tfConfig4$htmlTableId = {
base_path: 'https://www.azadvertizer.net/azgovvizv4/tablefilter/', rows_counter: true,
"@)
if ($tfCount -gt 10) {
$spectrum = "10, $tfCount"
if ($tfCount -gt 50) {
$spectrum = "10, 25, 50, $tfCount"
}
if ($tfCount -gt 100) {
$spectrum = "10, 30, 50, 100, $tfCount"
}
if ($tfCount -gt 500) {
$spectrum = "10, 30, 50, 100, 250, $tfCount"
}
if ($tfCount -gt 1000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, $tfCount"
}
if ($tfCount -gt 2000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, $tfCount"
}
if ($tfCount -gt 3000) {
$spectrum = "10, 30, 50, 100, 250, 500, 750, 1000, 1500, 3000, $tfCount"
}
[void]$htmlScopeInsights.AppendLine(@"
paging: {results_per_page: ['Records: ', [$spectrum]]},/*state: {types: ['local_storage'], filters: true, page_number: true, page_length: true, sort: true},*/
"@)
}
[void]$htmlScopeInsights.AppendLine(@"
btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true,
linked_filters: true,
col_3: 'select',
col_4: 'select',
col_5: 'select',
col_9: 'multiple',
col_10: 'select',
locale: 'en-US',
col_types: [
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'caseinsensitivestring',
'date',
'caseinsensitivestring'
],
watermark: ['', 'try owner||reader', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
extensions: [{ name: 'colsVisibility', text: 'Columns: ', enable_tick_all: true },{ name: 'sort' }]
};
var tf = new TableFilter('$htmlTableId', tfConfig4$htmlTableId);
tf.init();}}
</script>
"@)
}
else {
[void]$htmlScopeInsights.AppendLine(@"
<i class="fa fa-ban" aria-hidden="true"></i> $(($rbacAll).count) Role assignments
"@)
}
[void]$htmlScopeInsights.AppendLine(@'
</td></tr><!--rsi-->
'@)
#endregion ScopeInsightsRoleAssignments
if (-not $NoScopeInsights) {
$script:html += $htmlScopeInsights
}
if (-not $NoSingleSubscriptionOutput) {
if ($mgOrSub -eq 'sub') {
$htmlThisSubSingleOutput = $htmlSubscriptionOnlyStart
$htmlThisSubSingleOutput += $htmlScopeInsights
$htmlThisSubSingleOutput += $htmlSubscriptionOnlyEnd
$htmlThisSubSingleOutput | Set-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($HTMLPath)$($DirectorySeparatorChar)$($fileName)_$($subscriptionId).html" -Encoding utf8 -Force
$htmlThisSubSingleOutput = $null
}
}
if (-not $NoScopeInsights) {
if ($scopescnter % 50 -eq 0) {
$script:scopescnter = 0
$addContentDurationInSeconds = (Measure-Command { $script:html | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force }).TotalSeconds
Write-Host " append file duration: $addContentDurationInSeconds seconds"
$script:html = $null
}
}
if ($scopescnter % 50 -eq 0) {
showMemoryUsage
}
}