@@ -24,9 +24,22 @@ function Get-CIPPTenantAlignment {
2424 [Parameter (Mandatory = $false )]
2525 [string ]$TemplateId
2626 )
27+
28+ # Initialize overall stopwatch
29+ $OverallStopwatch = [System.Diagnostics.Stopwatch ]::StartNew()
30+ $SectionTimings = @ {}
31+
32+ # Measure template table initialization
33+ $sw = [System.Diagnostics.Stopwatch ]::StartNew()
2734 $TemplateTable = Get-CippTable - tablename ' templates'
2835 $TemplateFilter = " PartitionKey eq 'StandardsTemplateV2'"
36+ $sw.Stop ()
37+ $SectionTimings [' TemplateTableInit' ] = $sw.ElapsedMilliseconds
38+ Write-Verbose " Template table initialization took: $ ( $sw.ElapsedMilliseconds ) ms"
39+
2940 try {
41+ # Measure template loading
42+ $sw = [System.Diagnostics.Stopwatch ]::StartNew()
3043 # Get all standard templates
3144 $Templates = (Get-CIPPAzDataTableEntity @TemplateTable - Filter $TemplateFilter ) | ForEach-Object {
3245 $JSON = $_.JSON
@@ -42,12 +55,18 @@ function Get-CIPPTenantAlignment {
4255 $Data
4356 }
4457 }
58+ $sw.Stop ()
59+ $SectionTimings [' TemplateLoading' ] = $sw.ElapsedMilliseconds
60+ Write-Verbose " Template loading took: $ ( $sw.ElapsedMilliseconds ) ms"
61+ Write-Information " Loaded $ ( $Templates.Count ) templates in $ ( $sw.ElapsedMilliseconds ) ms"
4562
4663 if (-not $Templates ) {
4764 Write-Warning ' No templates found matching the criteria'
4865 return @ ()
4966 }
5067
68+ # Measure standards data retrieval
69+ $sw = [System.Diagnostics.Stopwatch ]::StartNew()
5170 # Get standards comparison data
5271 $StandardsTable = Get-CippTable - TableName ' CippStandardsReports'
5372 # this if statement is to bring down performance when running scheduled checks, we have to revisit this to a better query due to the extreme size this can get.
@@ -57,7 +76,13 @@ function Get-CIPPTenantAlignment {
5776 $filter = " PartitionKey ne 'StandardReport' and PartitionKey ne ''"
5877 }
5978 $AllStandards = Get-CIPPAzDataTableEntity @StandardsTable - Filter $filter
79+ $sw.Stop ()
80+ $SectionTimings [' StandardsDataRetrieval' ] = $sw.ElapsedMilliseconds
81+ Write-Verbose " Standards data retrieval took: $ ( $sw.ElapsedMilliseconds ) ms"
82+ Write-Information " Retrieved $ ( $AllStandards.Count ) standards records in $ ( $sw.ElapsedMilliseconds ) ms"
6083
84+ # Measure tenant filtering
85+ $sw = [System.Diagnostics.Stopwatch ]::StartNew()
6186 # Filter by tenant if specified
6287 $Standards = if ($TenantFilter ) {
6388 $AllStandards
@@ -66,6 +91,12 @@ function Get-CIPPTenantAlignment {
6691 $AllStandards | Where-Object { $_.PartitionKey -in $Tenants.defaultDomainName }
6792 }
6893 $TagTemplates = Get-CIPPAzDataTableEntity @TemplateTable
94+ $sw.Stop ()
95+ $SectionTimings [' TenantFiltering' ] = $sw.ElapsedMilliseconds
96+ Write-Verbose " Tenant filtering and tag template loading took: $ ( $sw.ElapsedMilliseconds ) ms"
97+
98+ # Measure tenant data structure building
99+ $sw = [System.Diagnostics.Stopwatch ]::StartNew()
69100 # Build tenant standards data structure
70101 $tenantData = @ {}
71102 foreach ($Standard in $Standards ) {
@@ -93,16 +124,32 @@ function Get-CIPPTenantAlignment {
93124 }
94125 }
95126 $TenantStandards = $tenantData
127+ $sw.Stop ()
128+ $SectionTimings [' TenantDataStructureBuilding' ] = $sw.ElapsedMilliseconds
129+ Write-Verbose " Tenant data structure building took: $ ( $sw.ElapsedMilliseconds ) ms"
130+ Write-Information " Built data structure for $ ( $tenantData.Count ) tenants in $ ( $sw.ElapsedMilliseconds ) ms"
96131
97132 $Results = [System.Collections.Generic.List [object ]]::new()
98133
134+ # Measure template processing
135+ $sw = [System.Diagnostics.Stopwatch ]::StartNew()
136+ $TemplateProcessingCount = 0
137+ $TemplateSectionTimings = @ {
138+ TenantScopeSetup = 0
139+ StandardsDataExtraction = 0
140+ StandardsSetBuilding = 0
141+ TenantComparison = 0
142+ }
99143 # Process each template against all tenants
100144 foreach ($Template in $Templates ) {
145+ $TemplateProcessingCount ++
101146 $TemplateStandards = $Template.standards
102147 if (-not $TemplateStandards ) {
103148 continue
104149 }
105150
151+ # Measure tenant scope setup
152+ $swTemplate = [System.Diagnostics.Stopwatch ]::StartNew()
106153 # Check if template has tenant assignments (scope)
107154 $TemplateAssignedTenants = @ ()
108155 $AppliestoAllTenants = $false
@@ -125,7 +172,11 @@ function Get-CIPPTenantAlignment {
125172 } else {
126173 $AppliestoAllTenants = $true
127174 }
175+ $swTemplate.Stop ()
176+ $TemplateSectionTimings.TenantScopeSetup += $swTemplate.ElapsedMilliseconds
128177
178+ # Measure standards data extraction
179+ $swTemplate = [System.Diagnostics.Stopwatch ]::StartNew()
129180 $StandardsData = foreach ($StandardKey in $TemplateStandards.PSObject.Properties.Name ) {
130181 $StandardConfig = $TemplateStandards .$StandardKey
131182 $StandardId = " standards.$StandardKey "
@@ -195,7 +246,11 @@ function Get-CIPPTenantAlignment {
195246 }
196247 }
197248 }
249+ $swTemplate.Stop ()
250+ $TemplateSectionTimings.StandardsDataExtraction += $swTemplate.ElapsedMilliseconds
198251
252+ # Measure standards set building
253+ $swTemplate = [System.Diagnostics.Stopwatch ]::StartNew()
199254 $AllStandards = $StandardsData.StandardId
200255 $AllStandardsArray = @ ($AllStandards )
201256 $ReportingDisabledStandards = ($StandardsData | Where-Object { -not $_.ReportingEnabled }).StandardId
@@ -206,7 +261,11 @@ function Get-CIPPTenantAlignment {
206261 foreach ($item in $TemplateAssignedTenants ) { [void ]$set.Add ($item ) }
207262 $set
208263 } else { $null }
264+ $swTemplate.Stop ()
265+ $TemplateSectionTimings.StandardsSetBuilding += $swTemplate.ElapsedMilliseconds
209266
267+ # Measure tenant comparison processing
268+ $swTemplate = [System.Diagnostics.Stopwatch ]::StartNew()
210269 foreach ($TenantName in $TenantStandards.Keys ) {
211270 # Check tenant scope with HashSet and cache tenant data
212271 if (-not $AppliestoAllTenants ) {
@@ -329,7 +388,34 @@ function Get-CIPPTenantAlignment {
329388
330389 $Results.Add ($Result )
331390 }
391+ $swTemplate.Stop ()
392+ $TemplateSectionTimings.TenantComparison += $swTemplate.ElapsedMilliseconds
393+ }
394+ $sw.Stop ()
395+ $SectionTimings [' TemplateProcessing' ] = $sw.ElapsedMilliseconds
396+ Write-Verbose " Template processing took: $ ( $sw.ElapsedMilliseconds ) ms for $TemplateProcessingCount templates"
397+ Write-Information " Processed $TemplateProcessingCount templates in $ ( $sw.ElapsedMilliseconds ) ms"
398+
399+ # Output template sub-section timings
400+ Write-Verbose ' Template processing breakdown:'
401+ Write-Information ' Template processing breakdown:'
402+ foreach ($Section in $TemplateSectionTimings.GetEnumerator () | Sort-Object Value - Descending) {
403+ $Percentage = if ($sw.ElapsedMilliseconds -gt 0 ) { [math ]::Round(($Section.Value / $sw.ElapsedMilliseconds ) * 100 , 2 ) } else { 0 }
404+ Write-Verbose " $ ( $Section.Key ) : $ ( $Section.Value ) ms ($Percentage %)"
405+ Write-Information " $ ( $Section.Key ) : $ ( $Section.Value ) ms ($Percentage %)"
406+ }
407+
408+ # Output timing summary
409+ $OverallStopwatch.Stop ()
410+ Write-Information ' === Get-CIPPTenantAlignment Performance Summary ==='
411+ Write-Information " Total execution time: $ ( $OverallStopwatch.ElapsedMilliseconds ) ms"
412+ Write-Verbose ' Section timings:'
413+ foreach ($Section in $SectionTimings.GetEnumerator () | Sort-Object Value - Descending) {
414+ $Percentage = [math ]::Round(($Section.Value / $OverallStopwatch.ElapsedMilliseconds ) * 100 , 2 )
415+ Write-Verbose " $ ( $Section.Key ) : $ ( $Section.Value ) ms ($Percentage %)"
416+ Write-Information " $ ( $Section.Key ) : $ ( $Section.Value ) ms ($Percentage %)"
332417 }
418+ Write-Information ' ========================================'
333419
334420 return $Results
335421 } catch {
0 commit comments