Skip to content

Commit 26ef3da

Browse files
authored
Merge pull request #980 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents aea5051 + f5f3736 commit 26ef3da

207 files changed

Lines changed: 1645 additions & 1491 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/CIPPDBCache/Push-ExecCIPPDBCache.ps1

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,19 @@ function Push-ExecCIPPDBCache {
4545
# Build the full function name
4646
$FullFunctionName = "Set-CIPPDBCache$Name"
4747

48-
# Check if function exists
49-
$Function = Get-Command -Name $FullFunctionName -ErrorAction SilentlyContinue
48+
# Cache the resolved command per process so back-to-back HTTP-driven refreshes
49+
# don't repeat the module command-table walk.
50+
if (-not $script:CIPPDBCacheFunctionLookup) {
51+
$script:CIPPDBCacheFunctionLookup = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::OrdinalIgnoreCase)
52+
Write-Information "[CacheInit] CIPPDBCacheFunctionLookup initialized in PID $PID"
53+
}
54+
if ($script:CIPPDBCacheFunctionLookup.ContainsKey($FullFunctionName)) {
55+
Write-Information "[CacheHit] CIPPDBCacheFunctionLookup PID=$PID Key=$FullFunctionName Size=$($script:CIPPDBCacheFunctionLookup.Count)"
56+
} else {
57+
Write-Information "[CacheMiss] CIPPDBCacheFunctionLookup PID=$PID Key=$FullFunctionName Size=$($script:CIPPDBCacheFunctionLookup.Count) - resolving via Get-Command"
58+
$script:CIPPDBCacheFunctionLookup[$FullFunctionName] = Get-Command -Name $FullFunctionName -ErrorAction SilentlyContinue
59+
}
60+
$Function = $script:CIPPDBCacheFunctionLookup[$FullFunctionName]
5061
if (-not $Function) {
5162
throw "Function $FullFunctionName does not exist"
5263
}

Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Tests/Push-CIPPTest.ps1

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ function Push-CIPPTest {
1212

1313
Write-Information "Running test $TestId for tenant $TenantFilter"
1414

15+
# Per-process cache of resolved test function commands so that a flat orchestrator
16+
# firing thousands of activities doesn't repeat the module command-table walk
17+
# for every task.
18+
if (-not $script:CIPPTestFunctionLookup) {
19+
$script:CIPPTestFunctionLookup = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::OrdinalIgnoreCase)
20+
Write-Information "[CacheInit] CIPPTestFunctionLookup initialized in PID $PID"
21+
}
22+
1523
try {
1624
if ($TestId -like 'CustomScript-*') {
1725
$ScriptGuid = $TestId -replace '^CustomScript-', ''
@@ -23,13 +31,20 @@ function Push-CIPPTest {
2331

2432
$FunctionName = "Invoke-CippTest$TestId"
2533

26-
if (-not (Get-Command $FunctionName -Module CIPPTests -ErrorAction SilentlyContinue)) {
34+
if ($script:CIPPTestFunctionLookup.ContainsKey($FunctionName)) {
35+
Write-Information "[CacheHit] CIPPTestFunctionLookup PID=$PID Key=$FunctionName Size=$($script:CIPPTestFunctionLookup.Count)"
36+
} else {
37+
Write-Information "[CacheMiss] CIPPTestFunctionLookup PID=$PID Key=$FunctionName Size=$($script:CIPPTestFunctionLookup.Count) - resolving via Get-Command"
38+
$script:CIPPTestFunctionLookup[$FunctionName] = Get-Command $FunctionName -Module CIPPTests -ErrorAction SilentlyContinue
39+
}
40+
$TestCommand = $script:CIPPTestFunctionLookup[$FunctionName]
41+
if (-not $TestCommand) {
2742
Write-LogMessage -API 'Tests' -tenant $TenantFilter -message "Test function not found: $FunctionName" -sev Error
2843
return @{ testRun = $false }
2944
}
3045

3146
Write-Information "Executing $FunctionName for $TenantFilter"
32-
& $FunctionName -Tenant $TenantFilter
47+
& $TestCommand -Tenant $TenantFilter
3348
Write-Host "Returning true, test has run for $tenantFilter"
3449
return @{ testRun = $true }
3550

Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Tests/Push-CIPPTestsList.ps1

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@ function Push-CIPPTestsList {
2222
try {
2323
Write-Information "Building test suite list for tenant: $TenantFilter"
2424

25-
# Check if tenant has data before emitting any work
26-
$DbCounts = Get-CIPPDbItem -TenantFilter $TenantFilter -CountsOnly
27-
if (($DbCounts | Measure-Object -Property DataCount -Sum).Sum -eq 0) {
28-
Write-Information "Tenant $TenantFilter has no data in database. Skipping tests."
29-
return @()
25+
# The orchestrator (Start-CIPPDBTestsRun) already filtered the tenant list to those
26+
# with cached data, so the previous per-tenant `Get-CIPPDbItem -CountsOnly` recheck
27+
# was a redundant Table query (one extra round-trip per tenant). The orchestrator
28+
# may pass SkipDbCheck=$true when it has already verified data presence; otherwise
29+
# we fall back to a check here for any direct invocations.
30+
if (-not $Item.SkipDbCheck) {
31+
$DbCounts = Get-CIPPDbItem -TenantFilter $TenantFilter -CountsOnly
32+
if (($DbCounts | Measure-Object -Property DataCount -Sum).Sum -eq 0) {
33+
Write-Information "Tenant $TenantFilter has no data in database. Skipping tests."
34+
return @()
35+
}
3036
}
3137

3238
# Emit one task per suite — suite names must match the ValidateSet in Invoke-CIPPTestCollection.

Modules/CIPPCore/Public/Add-CIPPDbItem.ps1

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ function Add-CIPPDbItem {
2929
$Batch = [System.Collections.Generic.List[hashtable]]::new()
3030
$NewRowKeys = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
3131
$TotalProcessed = 0
32+
# Cache regex instances so each row pays only the match cost, not regex compilation.
33+
# Two passes preserve the original semantics: path/wildcard chars → '_', control chars → stripped.
34+
$RowKeyPathRegex = [regex]::new('[/\\#?]')
35+
$RowKeyControlRegex = [regex]::new('[\u0000-\u001F\u007F-\u009F]')
3236

3337
if ($TenantFilter -match '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$') {
3438
try {
35-
$TenantFilter = (Get-Tenants -TenantFilter $TenantFilter -IncludeErrors | Select-Object -First 1).defaultDomainName
39+
$TenantLookup = @(Get-Tenants -TenantFilter $TenantFilter -IncludeErrors)
40+
if ($TenantLookup.Count -gt 0) { $TenantFilter = $TenantLookup[0].defaultDomainName }
3641
} catch {}
3742
}
3843
}
@@ -48,7 +53,7 @@ function Add-CIPPDbItem {
4853
foreach ($Item in @($InputObject)) {
4954
if ($null -eq $Item) { continue }
5055
$ItemId = $Item.ExternalDirectoryObjectId ?? $Item.id ?? $Item.Identity ?? $Item.skuId ?? $Item.userPrincipalName ?? [guid]::NewGuid().ToString()
51-
$RowKey = "$Type-$ItemId" -replace '[/\\#?]', '_' -replace '[\u0000-\u001F\u007F-\u009F]', ''
56+
$RowKey = $RowKeyControlRegex.Replace($RowKeyPathRegex.Replace("$Type-$ItemId", '_'), '')
5257
if ($NewRowKeys.Add($RowKey)) {
5358
$Batch.Add(@{
5459
PartitionKey = $TenantFilter

Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-CIPPDBTestsRun.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,14 @@ function Start-CIPPDBTestsRun {
5858
return
5959
}
6060

61-
# Phase 1: Build per-tenant list activities (discover tests per tenant)
61+
# Phase 1: Build per-tenant list activities (discover tests per tenant).
62+
# The tenants below were already filtered by data presence above, so we pass
63+
# SkipDbCheck=$true to avoid a redundant CountsOnly round-trip per tenant.
6264
$Batch = foreach ($Tenant in $AllTenantsList) {
6365
@{
6466
FunctionName = 'CIPPTestsList'
6567
TenantFilter = $Tenant
68+
SkipDbCheck = $true
6669
}
6770
}
6871

Modules/CIPPCore/Public/Get-CIPPDbItem.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ function Get-CIPPDbItem {
6262
$Conditions.Add('DataCount ge 0')
6363
}
6464
$Filter = [string]::Join(' and ', $Conditions)
65+
# -Property does the projection server-side; the trailing Select-Object was
66+
# redundant (and rebuilt every row as a NoteProperty bag, slowing later filters).
6567
$Results = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property 'PartitionKey', 'RowKey', 'DataCount', 'Timestamp'
66-
$Results = $Results | Select-Object PartitionKey, RowKey, DataCount, Timestamp
6768
} else {
6869
if (-not $Type) {
6970
throw 'Type parameter is required when CountsOnly is not specified'

Modules/CIPPCore/Public/Get-CIPPDomainAnalyser.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ function Get-CIPPDomainAnalyser {
1414
#>
1515
[CmdletBinding()]
1616
param([string]$TenantFilter)
17+
18+
if (-not $script:CIPPDomainAnalyserCache) {
19+
$script:CIPPDomainAnalyserCache = @{}
20+
}
21+
$CacheKey = if ([string]::IsNullOrEmpty($TenantFilter)) { 'AllTenants' } else { $TenantFilter }
22+
$CacheNow = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
23+
$CachedEntry = $script:CIPPDomainAnalyserCache[$CacheKey]
24+
if ($CachedEntry -and ($CacheNow - $CachedEntry.Timestamp) -lt 300) {
25+
return $CachedEntry.Results
26+
}
27+
1728
$DomainTable = Get-CIPPTable -Table 'Domains'
1829

1930
# Get all the things
@@ -43,5 +54,6 @@ function Get-CIPPDomainAnalyser {
4354
} catch {
4455
$Results = @()
4556
}
57+
$script:CIPPDomainAnalyserCache[$CacheKey] = @{ Results = $Results; Timestamp = $CacheNow }
4658
return $Results
4759
}

Modules/CIPPCore/Public/Get-CippDbRole.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function Get-CippDbRole {
1111
[switch]$CisaHighlyPrivilegedRoles
1212
)
1313

14-
$Roles = New-CIPPDbRequest -TenantFilter $TenantFilter -Type 'Roles'
14+
$Roles = Get-CIPPTestData -TenantFilter $TenantFilter -Type 'Roles'
1515

1616
if ($IncludePrivilegedRoles) {
1717
$PrivilegedRoleTemplateIds = @(

Modules/CIPPCore/Public/Get-CippDbRoleMembers.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ function Get-CippDbRoleMembers {
88
[string]$RoleTemplateId
99
)
1010

11-
$RoleAssignments = New-CIPPDbRequest -TenantFilter $TenantFilter -Type 'RoleAssignmentScheduleInstances'
12-
$RoleEligibilities = New-CIPPDbRequest -TenantFilter $TenantFilter -Type 'RoleEligibilitySchedules'
13-
$DirectRoleAssignments = New-CIPPDbRequest -TenantFilter $TenantFilter -Type 'Roles' | Where-Object { $_.roleTemplateId -eq $RoleTemplateId } | Select-Object -ExpandProperty members
11+
$RoleAssignments = Get-CIPPTestData -TenantFilter $TenantFilter -Type 'RoleAssignmentScheduleInstances'
12+
$RoleEligibilities = Get-CIPPTestData -TenantFilter $TenantFilter -Type 'RoleEligibilitySchedules'
13+
$DirectRoleAssignments = Get-CIPPTestData -TenantFilter $TenantFilter -Type 'Roles' | Where-Object { $_.roleTemplateId -eq $RoleTemplateId } | Select-Object -ExpandProperty members
1414

1515
$ActiveMembers = $RoleAssignments | Where-Object {
1616
$_.roleDefinitionId -eq $RoleTemplateId -and $_.assignmentType -eq 'Assigned'

Modules/CIPPCore/Public/Invoke-CIPPDBCacheCollection.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,13 @@ function Invoke-CIPPDBCacheCollection {
181181
Write-Information " [$CollectionType] Collecting $CacheType for $TenantFilter"
182182
& $FullFunctionName @Params
183183
$ItemStopwatch.Stop()
184-
$ElapsedSeconds = [math]::Round($ItemStopwatch.Elapsed.TotalSeconds, 3)
184+
$ElapsedSeconds = '{0:N3}' -f $ItemStopwatch.Elapsed.TotalSeconds
185185
$Timings.Add("$CacheType : ${ElapsedSeconds}s")
186186
Write-Information " [$CollectionType] Completed $CacheType for $TenantFilter - Took ${ElapsedSeconds} seconds"
187187
$SuccessCount++
188188
} catch {
189189
$ItemStopwatch.Stop()
190-
$ElapsedSeconds = [math]::Round($ItemStopwatch.Elapsed.TotalSeconds, 3)
190+
$ElapsedSeconds = '{0:N3}' -f $ItemStopwatch.Elapsed.TotalSeconds
191191
$FailedCount++
192192
$Errors.Add("$CacheType : $($_.Exception.Message)")
193193
$Timings.Add("$CacheType : ${ElapsedSeconds}s (FAILED)")
@@ -196,7 +196,7 @@ function Invoke-CIPPDBCacheCollection {
196196
}
197197

198198
$CollectionStopwatch.Stop()
199-
$TotalElapsed = [math]::Round($CollectionStopwatch.Elapsed.TotalSeconds, 3)
199+
$TotalElapsed = '{0:N3}' -f $CollectionStopwatch.Elapsed.TotalSeconds
200200
$Summary = "$CollectionType collection for $TenantFilter completed in ${TotalElapsed} seconds - $SuccessCount succeeded, $FailedCount failed out of $($CacheTypes.Count)"
201201
Write-Information $Summary
202202
Write-Information " Timings: $($Timings -join ' | ')"

0 commit comments

Comments
 (0)