Skip to content

Commit 02be9d3

Browse files
committed
progress stuffs
1 parent 63e6f41 commit 02be9d3

File tree

3 files changed

+226
-38
lines changed

3 files changed

+226
-38
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
function Push-ExecJITAdminListAllTenants {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
#>
6+
param($Item)
7+
8+
$Tenant = Get-Tenants -TenantFilter $Item.customerId
9+
$DomainName = $Tenant.defaultDomainName
10+
Write-Host "Processing push queue for JIT Admin for tenant: $DomainName"
11+
$Table = Get-CIPPTable -TableName CacheJITAdmin
12+
13+
try {
14+
# Get schema extensions
15+
$Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } | Select-Object -First 1
16+
17+
# Query users with JIT Admin enabled
18+
$Query = @{
19+
TenantFilter = $DomainName # Use $DomainName for the current tenant
20+
Endpoint = 'users'
21+
Parameters = @{
22+
'$count' = 'true'
23+
'$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)"
24+
'$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false" # Fetches both states to cache current status
25+
}
26+
}
27+
$Users = Get-GraphRequestList @Query | Where-Object { $_.id }
28+
29+
if ($Users) {
30+
# Get role memberships
31+
$BulkRequests = $Users | ForEach-Object { @(
32+
@{
33+
id = $_.id
34+
method = 'GET'
35+
url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName"
36+
}
37+
)
38+
}
39+
# Ensure $BulkRequests is not empty or null before making the bulk request
40+
if ($BulkRequests -and $BulkRequests.Count -gt 0) {
41+
$RoleResults = New-GraphBulkRequest -tenantid $DomainName -Requests @($BulkRequests)
42+
43+
# Format the data
44+
$Results = $Users | ForEach-Object {
45+
$currentUser = $_ # Capture current user in the loop
46+
$MemberOf = @() # Initialize as empty array
47+
if ($RoleResults) {
48+
$userRoleResult = $RoleResults | Where-Object -Property id -EQ $currentUser.id
49+
if ($userRoleResult -and $userRoleResult.body -and $userRoleResult.body.value) {
50+
$MemberOf = $userRoleResult.body.value | Select-Object displayName, id
51+
}
52+
}
53+
54+
$jitAdminData = $currentUser.($Schema.id)
55+
$jitAdminEnabled = if ($jitAdminData -and $jitAdminData.PSObject.Properties['jitAdminEnabled']) { $jitAdminData.jitAdminEnabled } else { $false }
56+
$jitAdminExpiration = if ($jitAdminData -and $jitAdminData.PSObject.Properties['jitAdminExpiration']) { $jitAdminData.jitAdminExpiration } else { $null }
57+
58+
[PSCustomObject]@{
59+
id = $currentUser.id
60+
displayName = $currentUser.displayName
61+
userPrincipalName = $currentUser.userPrincipalName
62+
accountEnabled = $currentUser.accountEnabled
63+
jitAdminEnabled = $jitAdminEnabled
64+
jitAdminExpiration = $jitAdminExpiration
65+
memberOf = ($MemberOf | ConvertTo-Json -Depth 5 -Compress) # Store as JSON string
66+
}
67+
}
68+
69+
# Add to Azure Table
70+
foreach ($result in $Results) {
71+
$GUID = (New-Guid).Guid
72+
$GraphRequest = @{
73+
JITAdminUser = ($result | ConvertTo-Json -Depth 10 -Compress)
74+
RowKey = [string]$GUID
75+
PartitionKey = 'JITAdminUsers' # Use the specified partition key
76+
Tenant = [string]$DomainName
77+
UserId = [string]$result.id # Add UserId for easier querying if needed
78+
UserUPN = [string]$result.userPrincipalName # Add UserUPN for easier querying
79+
}
80+
Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null
81+
}
82+
} else {
83+
# No users with JIT Admin attributes found, or no users at all
84+
Write-Host "No JIT Admin users or no users found to process for tenant $DomainName."
85+
}
86+
} else {
87+
Write-Host "No users found for tenant $DomainName."
88+
}
89+
90+
} catch {
91+
$GUID = (New-Guid).Guid
92+
$ErrorRecord = $_ | Select-Object *
93+
$ErrorMessage = "Could not process JIT Admin users for Tenant: $($DomainName). Error: $($_.Exception.Message)"
94+
if ($_.ScriptStackTrace) {
95+
$ErrorMessage += " StackTrace: $($_.ScriptStackTrace)"
96+
}
97+
$ErrorJson = ConvertTo-Json -InputObject @{
98+
Tenant = $DomainName
99+
Error = $ErrorMessage
100+
Exception = ($_.Exception | ConvertTo-Json -Depth 3 -Compress)
101+
FullError = ($ErrorRecord | ConvertTo-Json -Depth 3 -Compress)
102+
Timestamp = (Get-Date).ToString('s')
103+
}
104+
$GraphRequest = @{
105+
JITAdminUserError = [string]$ErrorJson
106+
RowKey = [string]$GUID
107+
PartitionKey = 'JITAdminUsers_Error' # Differentiate errors
108+
Tenant = [string]$DomainName
109+
}
110+
Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null
111+
Write-Error ('Error processing JIT Admin for {0}: {1}' -f $DomainName, $_.Exception.Message)
112+
}
113+
}

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1

Lines changed: 112 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,51 +10,126 @@ function Invoke-ExecJITAdmin {
1010
[CmdletBinding()]
1111
param($Request, $TriggerMetadata)
1212

13-
$APIName = 'ExecJITAdmin'
13+
$APIName = $Request.Params.CIPPEndpoint
1414
$User = $Request.Headers
15-
$TenantFilter = $Request.body.TenantFilter.value ? $Request.body.TenantFilter.value : $Request.body.TenantFilter
16-
Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug'
15+
$TenantFilter = $Request.Body.tenantFilter.value ? $Request.Body.tenantFilter.value : $Request.Body.tenantFilter
16+
Write-LogMessage -Headers $User -API $APIName -message 'Accessed this API' -Sev 'Debug'
1717

1818
if ($Request.Query.Action -eq 'List') {
1919
$Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } | Select-Object -First 1
20-
$Query = @{
21-
TenantFilter = $Request.Query.TenantFilter
22-
Endpoint = 'users'
23-
Parameters = @{
24-
'$count' = 'true'
25-
'$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)"
26-
'$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false"
20+
if ($TenantFilter -ne 'AllTenants') {
21+
$Query = @{
22+
TenantFilter = $Request.Query.TenantFilter
23+
Endpoint = 'users'
24+
Parameters = @{
25+
'$count' = 'true'
26+
'$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)"
27+
'$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false"
28+
}
2729
}
28-
}
29-
$Users = Get-GraphRequestList @Query | Where-Object { $_.id }
30-
$BulkRequests = $Users | ForEach-Object { @(
31-
@{
32-
id = $_.id
33-
method = 'GET'
34-
url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName"
30+
$Users = Get-GraphRequestList @Query | Where-Object { $_.id }
31+
$BulkRequests = $Users | ForEach-Object { @(
32+
@{
33+
id = $_.id
34+
method = 'GET'
35+
url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName"
36+
}
37+
)
38+
}
39+
# Use $TenantFilter consistently, which is derived from Body or Query params at line 15
40+
$RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests @($BulkRequests)
41+
#Write-Information ($RoleResults | ConvertTo-Json -Depth 10 )
42+
$Results = $Users | ForEach-Object {
43+
$MemberOf = ($RoleResults | Where-Object -Property id -EQ $_.id).body.value | Select-Object displayName, id
44+
[PSCustomObject]@{
45+
id = $_.id
46+
displayName = $_.displayName
47+
userPrincipalName = $_.userPrincipalName
48+
accountEnabled = $_.accountEnabled
49+
jitAdminEnabled = $_.($Schema.id).jitAdminEnabled
50+
jitAdminExpiration = $_.($Schema.id).jitAdminExpiration
51+
memberOf = $MemberOf
3552
}
36-
)
37-
}
38-
$RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests @($BulkRequests)
39-
#Write-Information ($RoleResults | ConvertTo-Json -Depth 10 )
40-
$Results = $Users | ForEach-Object {
41-
$MemberOf = ($RoleResults | Where-Object -Property id -EQ $_.id).body.value | Select-Object displayName, id
42-
[PSCustomObject]@{
43-
id = $_.id
44-
displayName = $_.displayName
45-
userPrincipalName = $_.userPrincipalName
46-
accountEnabled = $_.accountEnabled
47-
jitAdminEnabled = $_.($Schema.id).jitAdminEnabled
48-
jitAdminExpiration = $_.($Schema.id).jitAdminExpiration
49-
memberOf = $MemberOf
5053
}
51-
}
5254

53-
#Write-Information ($Results | ConvertTo-Json -Depth 10)
54-
$Body = @{
55-
Results = @($Results)
56-
Metadata = @{
57-
Parameters = $Query.Parameters
55+
#Write-Information ($Results | ConvertTo-Json -Depth 10)
56+
$Body = @{
57+
Results = @($Results)
58+
Metadata = @{
59+
Parameters = $Query.Parameters
60+
}
61+
}
62+
} else {
63+
# AllTenants logic
64+
$Results = [System.Collections.Generic.List[object]]::new()
65+
$Metadata = @{}
66+
# Assumed table name for JIT Admin cache. User might need to adjust.
67+
$Table = Get-CIPPTable -TableName CacheJITAdmin
68+
$PartitionKey = 'JITAdminUsers' # Assumed partition key
69+
70+
# Filter for recent data, e.g., last 60 minutes. Orchestrator populates this.
71+
$Filter = "PartitionKey eq '$PartitionKey'"
72+
$Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-1)
73+
74+
$QueueReference = '{0}-{1}' -f $Request.Query.TenantFilter, $PartitionKey # $TenantFilter is 'AllTenants'
75+
$RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' }
76+
77+
if ($RunningQueue) {
78+
$Metadata = [PSCustomObject]@{
79+
QueueMessage = 'Still loading JIT Admin data for all tenants. Please check back in a few more minutes.'
80+
}
81+
$Results.Add([PSCustomObject]@{ Waiting = $true })
82+
} elseif (!$dRows -and !$RunningQueue) {
83+
$TenantList = Get-Tenants -IncludeErrors
84+
$QueueLink = if ($Request.RequestUri) { $Request.RequestUri.ToString() -replace $Request.Query.Action, 'List' } else { '/identity/administration/users/jit-admin?Action=List&TenantFilter=AllTenants' } # Fallback link
85+
$Queue = New-CippQueueEntry -Name 'JIT Admin List - All Tenants' -Link $QueueLink -Reference $QueueReference -TotalTasks ($TenantList | Measure-Object).Count
86+
87+
$Metadata = [PSCustomObject]@{
88+
QueueMessage = 'Loading JIT Admin data for all tenants. Please check back in a few minutes.'
89+
}
90+
$InputObject = [PSCustomObject]@{
91+
OrchestratorName = 'JITAdminListAllTenantsOrchestrator' # Assumed orchestrator name
92+
QueueFunction = @{
93+
FunctionName = 'GetTenants' # Generic entry, durable function handles per-tenant logic
94+
QueueId = $Queue.RowKey
95+
TenantParams = @{
96+
IncludeErrors = $true
97+
}
98+
DurableName = 'ExecJITAdminListAllTenants'
99+
}
100+
SkipLog = $true
101+
}
102+
Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress)
103+
$Results.Add([PSCustomObject]@{ Waiting = $true })
104+
} else {
105+
# $dRows exist
106+
foreach ($row in $Rows) {
107+
# Assuming $row.JITUserObject contains the serialized PSCustomObject for the user's JIT details
108+
# And $row.TenantId (or $row.TenantDisplayName) contains the tenant identifier
109+
try {
110+
$UserObject = $row.JITUserObject | ConvertFrom-Json
111+
$Results.Add(
112+
[PSCustomObject]@{
113+
Tenant = $row.TenantId # Or TenantDisplayName, ensure orchestrator stores this
114+
id = $UserObject.id
115+
displayName = $UserObject.displayName
116+
userPrincipalName = $UserObject.userPrincipalName
117+
accountEnabled = $UserObject.accountEnabled
118+
jitAdminEnabled = $UserObject.jitAdminEnabled
119+
jitAdminExpiration = $UserObject.jitAdminExpiration
120+
memberOf = $UserObject.memberOf # This should be an array of role objects
121+
}
122+
)
123+
} catch {
124+
Write-LogMessage -Headers $User -API $APIName -message "Failed to process cached JIT admin row for Tenant $($row.TenantId), RowKey $($row.RowKey). Error: $($_.Exception.Message)" -Sev 'Warning'
125+
# Optionally add a placeholder or skip if critical
126+
}
127+
}
128+
$Metadata = @{ Info = 'Displaying cached JIT Admin data for all tenants.' }
129+
}
130+
$Body = @{
131+
Results = @($Results)
132+
Metadata = $Metadata
58133
}
59134
}
60135
} else {

Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ function Test-CIPPAccessPermissions {
133133
$ApplicationToken = Get-GraphToken -returnRefresh $true -SkipCache $true -AsApp $true
134134
$ApplicationTokenDetails = Read-JwtAccessDetails -Token $ApplicationToken.access_token -erroraction SilentlyContinue | Select-Object
135135

136-
$LastUpdate = [DateTime]::SpecifyKind($GraphPermissions.Timestamp.DateTime, [DateTimeKind]::Utc)
136+
$LastUpdate = [DateTime]::SpecifyKind($GraphPermissions.Timestamp.ToString('yyyy-MM-ddTHH:mm:ssZ'), [DateTimeKind]::Utc)
137137
$CpvTable = Get-CippTable -tablename 'cpvtenants'
138138
$CpvRefresh = Get-CippAzDataTableEntity @CpvTable -Filter "PartitionKey eq 'Tenant'"
139139
$TenantList = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -ne $env:TenantID -and $_.Excluded -eq $false }

0 commit comments

Comments
 (0)