Skip to content

Commit 21f2133

Browse files
tenantgroups
1 parent 6cab31a commit 21f2133

File tree

1 file changed

+109
-31
lines changed

1 file changed

+109
-31
lines changed
Lines changed: 109 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
1+
if (-not $script:TenantGroupsCache) {
2+
$script:TenantGroupsCache = @{
3+
Groups = $null
4+
Members = $null
5+
LastRefresh = $null
6+
MembersByGroup = $null # Dictionary: GroupId -> members array
7+
}
8+
}
9+
10+
# Result cache: keyed by "GroupId|TenantFilter|Dynamic"
11+
if (-not $script:TenantGroupsResultCache) {
12+
$script:TenantGroupsResultCache = @{}
13+
}
14+
115
function Get-TenantGroups {
216
<#
317
.SYNOPSIS
418
Get tenant groups
519
.DESCRIPTION
6-
Get tenant groups from Azure Table Storage
20+
Get tenant groups from Azure Table Storage with performance optimizations
21+
using script-scoped caches and in-memory indexing
722
.PARAMETER GroupId
823
The group id to filter on
924
.PARAMETER TenantFilter
1025
The tenant filter to apply to get the groups for a specific tenant
26+
.PARAMETER Dynamic
27+
Filter to only dynamic groups
1128
#>
1229
[CmdletBinding()]
1330
param(
@@ -16,8 +33,14 @@ function Get-TenantGroups {
1633
[switch]$Dynamic
1734
)
1835

19-
$GroupTable = Get-CippTable -tablename 'TenantGroups'
20-
$MembersTable = Get-CippTable -tablename 'TenantGroupMembers'
36+
# Build cache key for result caching
37+
$CacheKey = "$GroupId|$TenantFilter|$($Dynamic.IsPresent)"
38+
39+
# Return cached result if available
40+
if ($script:TenantGroupsResultCache.ContainsKey($CacheKey)) {
41+
Write-Verbose "Returning cached result for: $CacheKey"
42+
return $script:TenantGroupsResultCache[$CacheKey]
43+
}
2144

2245
# Early exit if specific GroupId requested but not allowed
2346
if ($GroupId -and $script:CippAllowedGroupsStorage -and $script:CippAllowedGroupsStorage.Value) {
@@ -26,6 +49,34 @@ function Get-TenantGroups {
2649
}
2750
}
2851

52+
# Load table data into cache if not already loaded
53+
if (-not $script:TenantGroupsCache.Groups -or -not $script:TenantGroupsCache.Members) {
54+
Write-Verbose 'Loading TenantGroups and TenantGroupMembers tables into cache'
55+
56+
$GroupTable = Get-CippTable -tablename 'TenantGroups'
57+
$MembersTable = Get-CippTable -tablename 'TenantGroupMembers'
58+
59+
$GroupTable.Filter = "PartitionKey eq 'TenantGroup'"
60+
61+
# Load all groups and members once
62+
$script:TenantGroupsCache.Groups = @(Get-CIPPAzDataTableEntity @GroupTable)
63+
$script:TenantGroupsCache.Members = @(Get-CIPPAzDataTableEntity @MembersTable)
64+
$script:TenantGroupsCache.LastRefresh = Get-Date
65+
66+
# Build MembersByGroup index: GroupId -> array of member objects
67+
$script:TenantGroupsCache.MembersByGroup = @{}
68+
foreach ($Member in $script:TenantGroupsCache.Members) {
69+
$GId = $Member.GroupId
70+
if (-not $script:TenantGroupsCache.MembersByGroup.ContainsKey($GId)) {
71+
$script:TenantGroupsCache.MembersByGroup[$GId] = [System.Collections.Generic.List[object]]::new()
72+
}
73+
$script:TenantGroupsCache.MembersByGroup[$GId].Add($Member)
74+
}
75+
76+
Write-Verbose "Cache loaded: $($script:TenantGroupsCache.Groups.Count) groups, $($script:TenantGroupsCache.Members.Count) members"
77+
}
78+
79+
# Get tenants (already cached and fast per requirements)
2980
if ($TenantFilter -and $TenantFilter -ne 'allTenants') {
3081
$TenantParams = @{
3182
TenantFilter = $TenantFilter
@@ -38,51 +89,74 @@ function Get-TenantGroups {
3889
}
3990
$Tenants = Get-Tenants @TenantParams
4091

92+
$TenantByCustomerId = @{}
93+
foreach ($Tenant in $Tenants) {
94+
$TenantByCustomerId[$Tenant.customerId] = $Tenant
95+
}
96+
97+
$Groups = $script:TenantGroupsCache.Groups
98+
4199
if ($Dynamic.IsPresent) {
42-
$GroupTable.Filter = "PartitionKey eq 'TenantGroup' and GroupType eq 'dynamic'"
43-
} else {
44-
$GroupTable.Filter = "PartitionKey eq 'TenantGroup'"
100+
$Groups = $Groups | Where-Object { $_.GroupType -eq 'dynamic' }
45101
}
46102

47103
if ($GroupId) {
48-
$Groups = Get-CIPPAzDataTableEntity @GroupTable -Filter "RowKey eq '$GroupId'"
49-
$AllMembers = Get-CIPPAzDataTableEntity @MembersTable -Filter "GroupId eq '$GroupId'"
50-
} else {
51-
$Groups = Get-CIPPAzDataTableEntity @GroupTable
52-
$AllMembers = Get-CIPPAzDataTableEntity @MembersTable
104+
$Groups = $Groups | Where-Object { $_.RowKey -eq $GroupId }
105+
}
53106

54-
# Filter to allowed groups if restrictions apply
55-
if ($script:CippAllowedGroupsStorage -and $script:CippAllowedGroupsStorage.Value) {
56-
$Groups = $Groups | Where-Object { $script:CippAllowedGroupsStorage.Value -contains $_.RowKey }
57-
}
107+
if ($script:CippAllowedGroupsStorage -and $script:CippAllowedGroupsStorage.Value) {
108+
$Groups = $Groups | Where-Object { $script:CippAllowedGroupsStorage.Value -contains $_.RowKey }
58109
}
59110

60-
if (!$Groups) {
111+
if (!$Groups -or $Groups.Count -eq 0) {
112+
$script:TenantGroupsResultCache[$CacheKey] = @()
61113
return @()
62114
}
63115

116+
# Process results based on TenantFilter
64117
if ($TenantFilter -and $TenantFilter -ne 'allTenants') {
118+
# Return simplified group list for specific tenant
65119
$Results = [System.Collections.Generic.List[PSCustomObject]]::new()
66-
$Memberships = $AllMembers | Where-Object { $_.customerId -eq $Tenants.customerId }
67-
foreach ($Group in $Memberships) {
68-
$Group = $Groups | Where-Object { $_.RowKey -eq $Group.GroupId }
69-
if ($Group) {
70-
$Results.Add([PSCustomObject]@{
71-
Id = $Group.RowKey
72-
Name = $Group.Name
73-
Description = $Group.Description
74-
})
120+
$TargetCustomerId = $Tenants.customerId
121+
122+
foreach ($Group in $Groups) {
123+
$GroupMembers = $script:TenantGroupsCache.MembersByGroup[$Group.RowKey]
124+
125+
if ($GroupMembers) {
126+
# Check if this group has the target tenant as a member
127+
$HasTenant = $false
128+
foreach ($Member in $GroupMembers) {
129+
if ($Member.customerId -eq $TargetCustomerId) {
130+
$HasTenant = $true
131+
break
132+
}
133+
}
134+
135+
if ($HasTenant) {
136+
$Results.Add([PSCustomObject]@{
137+
Id = $Group.RowKey
138+
Name = $Group.Name
139+
Description = $Group.Description
140+
})
141+
}
75142
}
76143
}
77-
return $Results | Sort-Object Name
144+
145+
$FinalResults = $Results | Sort-Object Name
146+
$script:TenantGroupsResultCache[$CacheKey] = $FinalResults
147+
return $FinalResults
78148
} else {
149+
# Return full group details with members
79150
$Results = [System.Collections.Generic.List[PSCustomObject]]::new()
151+
80152
foreach ($Group in $Groups) {
81-
$Members = $AllMembers | Where-Object { $_.GroupId -eq $Group.RowKey }
153+
$GroupMembers = $script:TenantGroupsCache.MembersByGroup[$Group.RowKey]
82154
$MembersList = [System.Collections.Generic.List[hashtable]]::new()
83-
if ($Members) {
84-
foreach ($Member in $Members) {
85-
$Tenant = $Tenants | Where-Object { $Member.customerId -eq $_.customerId }
155+
156+
if ($GroupMembers) {
157+
foreach ($Member in $GroupMembers) {
158+
# Use indexed lookup instead of Where-Object
159+
$Tenant = $TenantByCustomerId[$Member.customerId]
86160
if ($Tenant) {
87161
$MembersList.Add(@{
88162
customerId = $Tenant.customerId
@@ -95,6 +169,7 @@ function Get-TenantGroups {
95169
} else {
96170
$SortedMembers = @()
97171
}
172+
98173
$Results.Add([PSCustomObject]@{
99174
Id = $Group.RowKey
100175
Name = $Group.Name
@@ -105,6 +180,9 @@ function Get-TenantGroups {
105180
Members = @($SortedMembers)
106181
})
107182
}
108-
return $Results | Sort-Object Name
183+
184+
$FinalResults = $Results | Sort-Object Name
185+
$script:TenantGroupsResultCache[$CacheKey] = $FinalResults
186+
return $FinalResults
109187
}
110188
}

0 commit comments

Comments
 (0)