Skip to content

Commit fa42a22

Browse files
authored
Merge pull request #947 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents c1bab95 + c79cf7b commit fa42a22

10 files changed

Lines changed: 165 additions & 35 deletions

File tree

Config/SAMManifest.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@
108108
"id": "dbb9058a-0e50-45d7-ae91-66909b5d4664",
109109
"type": "Role"
110110
},
111+
{
112+
"id": "7e05723c-0bb0-42da-be95-ae9f08a6e53c",
113+
"type": "Role"
114+
},
111115
{
112116
"id": "75359482-378d-4052-8f01-80520e7db3cd",
113117
"type": "Role"
@@ -344,6 +348,10 @@
344348
"id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311",
345349
"type": "Scope"
346350
},
351+
{
352+
"id": "0b5d694c-a244-4bde-86e6-eb5cd07730fe",
353+
"type": "Scope"
354+
},
347355
{
348356
"id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0",
349357
"type": "Scope"

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,22 +75,32 @@ function Start-UserTasksOrchestrator {
7575
# Cache Get-Command result to avoid repeated expensive reflection calls
7676
$CommandInfo = Get-Command -Name $task.Command -ErrorAction SilentlyContinue
7777
if (-not $CommandInfo) {
78-
Write-Information "Command '$($task.Command)' not found in currently loaded modules. Attempting Alerts module import."
79-
$ImportedCippAlerts = $false
80-
try {
81-
if (-not (Get-Module -Name 'CIPPAlerts')) {
82-
Import-Module CIPPAlerts -ErrorAction Stop
83-
$ImportedCippAlerts = $true
84-
Write-Information "Imported module 'CIPPAlerts' for command resolution retry."
85-
}
78+
# Resolve the required module from standardised command name patterns
79+
$ModuleToImport = switch -Wildcard ($task.Command) {
80+
'Invoke-CIPPStandard*' { 'CIPPStandards' }
81+
'Get-CIPPAlert*' { 'CIPPAlerts' }
82+
default { $null }
83+
}
8684

87-
$CommandInfo = Get-Command -Name $task.Command -ErrorAction Stop
88-
} catch {
89-
throw "Unable to resolve command '$($task.Command)' for scheduled task '$($task.Name)' after module import retry. $($_.Exception.Message)"
90-
} finally {
91-
if ($ImportedCippAlerts) {
92-
Remove-Module CIPPAlerts -ErrorAction SilentlyContinue
85+
if ($ModuleToImport) {
86+
Write-Information "Command '$($task.Command)' not found. Attempting import of '$ModuleToImport' module."
87+
$ImportedModule = $false
88+
try {
89+
if (-not (Get-Module -Name $ModuleToImport)) {
90+
Import-Module $ModuleToImport -ErrorAction Stop
91+
$ImportedModule = $true
92+
Write-Information "Imported module '$ModuleToImport' for command resolution retry."
93+
}
94+
$CommandInfo = Get-Command -Name $task.Command -ErrorAction Stop
95+
} catch {
96+
throw "Unable to resolve command '$($task.Command)' for scheduled task '$($task.Name)' after importing '$ModuleToImport'. $($_.Exception.Message)"
97+
} finally {
98+
if ($ImportedModule) {
99+
Remove-Module $ModuleToImport -ErrorAction SilentlyContinue
100+
}
93101
}
102+
} else {
103+
throw "Command '$($task.Command)' not found and no module could be resolved from the command name for scheduled task '$($task.Name)'."
94104
}
95105
}
96106
$HasTenantFilter = $CommandInfo.Parameters.ContainsKey('TenantFilter')

Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,21 @@ function Get-CIPPTenantAlignment {
380380

381381
foreach ($item in $ComparisonResults) {
382382
$IsAcceptedDeviation = $false
383+
$DeviationStatus = $null
383384
if ($IsDriftTemplate -and $item.ComplianceStatus -eq 'Non-Compliant') {
384385
$DeviationStatus = $TenantDriftStatuses[$item.StandardName]
385386
$IsAcceptedDeviation = $DeviationStatus -in @('Accepted', 'CustomerSpecific')
386387
}
387388

388-
if ($item.ComplianceStatus -eq 'Compliant' -or $IsAcceptedDeviation) { $CompliantStandards++ }
389+
# Update the item's compliance status and add deviation info for granular consumers
390+
if ($IsAcceptedDeviation) {
391+
$item.ComplianceStatus = if ($DeviationStatus -eq 'Accepted') { 'Accepted Deviation' } else { 'Customer Specific' }
392+
}
393+
if ($DeviationStatus) {
394+
$item | Add-Member -NotePropertyName 'DeviationStatus' -NotePropertyValue $DeviationStatus -Force
395+
}
396+
397+
if ($item.ComplianceStatus -in @('Compliant', 'Accepted Deviation', 'Customer Specific')) { $CompliantStandards++ }
389398
elseif ($item.ComplianceStatus -eq 'Non-Compliant') { $NonCompliantStandards++ }
390399
elseif ($item.ComplianceStatus -eq 'License Missing') { $LicenseMissingStandards++ }
391400
if ($item.ReportingDisabled) { $ReportingDisabledStandardsCount++ }
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
function Get-CIPPOAuthAppsReport {
2+
<#
3+
.SYNOPSIS
4+
Generates an OAuth consented applications report from the CIPP Reporting database
5+
6+
.DESCRIPTION
7+
Retrieves OAuth2 permission grants and enriches them with service principal data from the reporting database
8+
9+
.PARAMETER TenantFilter
10+
The tenant to generate the report for
11+
#>
12+
[CmdletBinding()]
13+
param(
14+
[Parameter(Mandatory = $true)]
15+
[string]$TenantFilter
16+
)
17+
18+
try {
19+
if ($TenantFilter -eq 'AllTenants') {
20+
$AllOAuthItems = Get-CIPPDbItem -TenantFilter 'allTenants' -Type 'OAuth2PermissionGrants'
21+
$Tenants = @($AllOAuthItems | Where-Object { $_.RowKey -ne 'OAuth2PermissionGrants-Count' } | Select-Object -ExpandProperty PartitionKey -Unique)
22+
23+
$TenantList = Get-Tenants -IncludeErrors
24+
$Tenants = $Tenants | Where-Object { $TenantList.defaultDomainName -contains $_ }
25+
26+
$AllResults = [System.Collections.Generic.List[PSCustomObject]]::new()
27+
foreach ($Tenant in $Tenants) {
28+
try {
29+
$TenantResults = Get-CIPPOAuthAppsReport -TenantFilter $Tenant
30+
foreach ($Result in $TenantResults) {
31+
$Result | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $Tenant -Force
32+
$AllResults.Add($Result)
33+
}
34+
} catch {
35+
Write-LogMessage -API 'OAuthAppsReport' -tenant $Tenant -message "Failed to get report for tenant: $($_.Exception.Message)" -sev Warning
36+
}
37+
}
38+
return $AllResults
39+
}
40+
41+
$OAuthGrants = @(New-CIPPDbRequest -TenantFilter $TenantFilter -Type 'OAuth2PermissionGrants')
42+
if (-not $OAuthGrants) {
43+
throw 'No OAuth2 permission grant data found in reporting database. Sync the report data first.'
44+
}
45+
46+
$ServicePrincipals = @(New-CIPPDbRequest -TenantFilter $TenantFilter -Type 'ServicePrincipals')
47+
$SPLookup = @{}
48+
foreach ($SP in $ServicePrincipals) {
49+
if ($SP.id) {
50+
$SPLookup[$SP.id] = $SP
51+
}
52+
}
53+
54+
$CacheTimestamp = (Get-CIPPDbItem -TenantFilter $TenantFilter -Type 'OAuth2PermissionGrants' | Where-Object { $_.Timestamp } | Sort-Object Timestamp -Descending | Select-Object -First 1).Timestamp
55+
56+
$Results = [System.Collections.Generic.List[PSCustomObject]]::new()
57+
foreach ($Grant in $OAuthGrants) {
58+
$SP = $SPLookup[$Grant.clientId]
59+
$Results.Add([PSCustomObject]@{
60+
Name = if ($SP) { $SP.displayName } else { $Grant.clientId }
61+
ApplicationID = if ($SP) { $SP.appId } else { '' }
62+
ObjectID = $Grant.clientId
63+
Scope = ($Grant.scope -join ',')
64+
StartTime = $Grant.startTime
65+
CacheTimestamp = $CacheTimestamp
66+
})
67+
}
68+
69+
return $Results | Sort-Object -Property Name
70+
71+
} catch {
72+
Write-LogMessage -API 'OAuthAppsReport' -tenant $TenantFilter -message "Failed to generate OAuth apps report: $($_.Exception.Message)" -sev Error
73+
throw
74+
}
75+
}

Modules/CIPPCore/Public/New-CIPPBackup.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ function New-CIPPBackup {
6565
} else {
6666
Get-AzDataTableEntity @Table
6767
}
68+
if ($CSVTable -eq 'Config') {
69+
$Entities = $Entities | Where-Object { $_.PartitionKey -ne 'OffloadFunctions' }
70+
}
6871
$Entities | Select-Object * -ExcludeProperty DomainAnalyser, table, Timestamp, ETag, Results | Select-Object *, @{l = 'table'; e = { $CSVTable } }
6972
}
7073
$RowKey = 'CIPPBackup' + '_' + (Get-Date).ToString('yyyy-MM-dd-HHmm')

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ function Invoke-ListGraphRequest {
117117
}
118118

119119
if ($Request.Query.AsApp) {
120-
$GraphRequestParams.AsApp = $true
120+
$GraphRequestParams.AsApp = [System.Convert]::ToBoolean($Request.Query.AsApp)
121121
}
122122

123123
$Metadata = $GraphRequestParams
@@ -155,9 +155,10 @@ function Invoke-ListGraphRequest {
155155
}
156156

157157
if ($Results | Where-Object { $_.PSObject.Properties.Name -contains 'nextLink' }) {
158-
if (![string]::IsNullOrEmpty($Results.nextLink) -and $Request.Query.TenantFilter -ne 'AllTenants') {
159-
Write-Host "NextLink: $($Results.nextLink | Where-Object { $_ } | Select-Object -Last 1)"
160-
$Metadata['nextLink'] = $Results.nextLink | Where-Object { $_ } | Select-Object -Last 1
158+
$NextLink = $Results.nextLink | Where-Object { $_ } | Select-Object -Last 1
159+
if ($NextLink -and $Request.Query.TenantFilter -ne 'AllTenants') {
160+
Write-Host "NextLink: $NextLink"
161+
$Metadata['nextLink'] = $NextLink
161162
}
162163
# Remove nextLink trailing object only if it’s the last item
163164
$Results = $Results | Where-Object { $_.PSObject.Properties.Name -notcontains 'nextLink' }

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ function Invoke-ExecOffloadFunctions {
5757
Body = $CurrentState
5858
})
5959
} else {
60+
if ($env:CIPP_HOSTED -eq 'true') {
61+
return ([HttpResponseContext]@{
62+
StatusCode = [HttpStatusCode]::Forbidden
63+
Body = @{ results = 'Offload function configuration is not available on hosted instances. Please contact the helpdesk to make changes' }
64+
})
65+
}
66+
6067
Add-CIPPAzDataTableEntity @Table -Entity @{
6168
PartitionKey = 'OffloadFunctions'
6269
RowKey = 'OffloadFunctions'

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ function Invoke-ExecRestoreBackup {
5959
if ($_.table -like 'cache*') {
6060
return
6161
}
62+
if ($_.table -eq 'Config' -and $_.PartitionKey -eq 'OffloadFunctions') {
63+
return
64+
}
6265
if ($RestrictedTables -contains $_.table -and -not $IsSuperAdmin) {
6366
Write-Information "Skipping restricted table '$($_.table)' - user does not have superadmin rights"
6467
return
@@ -88,6 +91,9 @@ function Invoke-ExecRestoreBackup {
8891
if ($line.table -like 'cache*') {
8992
continue
9093
}
94+
if ($line.table -eq 'Config' -and $line.PartitionKey -eq 'OffloadFunctions') {
95+
continue
96+
}
9197
if ($RestrictedTables -contains $line.table -and -not $IsSuperAdmin) {
9298
Write-Information "Skipping restricted table '$($line.table)' - user does not have superadmin rights"
9399
continue

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListOAuthApps.ps1

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,40 @@ Function Invoke-ListOAuthApps {
77
#>
88
[CmdletBinding()]
99
param($Request, $TriggerMetadata)
10-
# Interact with query parameters or the body of the request.
10+
1111
$TenantFilter = $Request.Query.TenantFilter
12-
if ($TenantFilter -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $Tenants = $TenantFilter }
12+
$UseReportDB = $Request.Query.UseReportDB
1313

1414
try {
15-
$GraphRequest = foreach ($Tenant in $Tenants) {
15+
if ($UseReportDB -eq 'true') {
1616
try {
17-
$ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=id,displayName,appid" -tenantid $Tenant
18-
New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/oauth2PermissionGrants' -tenantid $Tenant | ForEach-Object {
19-
$CurrentServicePrincipal = ($ServicePrincipals | Where-Object -Property id -EQ $_.clientId)
20-
[PSCustomObject]@{
21-
Tenant = $Tenant
22-
Name = $CurrentServicePrincipal.displayName
23-
ApplicationID = $CurrentServicePrincipal.appid
24-
ObjectID = $_.clientId
25-
Scope = ($_.scope -join ',')
26-
StartTime = $_.startTime
27-
}
28-
}
17+
$GraphRequest = Get-CIPPOAuthAppsReport -TenantFilter $TenantFilter -ErrorAction Stop
2918
$StatusCode = [HttpStatusCode]::OK
3019
} catch {
31-
continue
20+
Write-Host "Error retrieving OAuth apps from report database: $($_.Exception.Message)"
21+
$StatusCode = [HttpStatusCode]::InternalServerError
22+
$GraphRequest = $_.Exception.Message
23+
}
24+
25+
return ([HttpResponseContext]@{
26+
StatusCode = $StatusCode
27+
Body = @($GraphRequest)
28+
})
29+
}
30+
31+
# Live data - single tenant only
32+
$ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=id,displayName,appid&`$top=999" -tenantid $TenantFilter
33+
$GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/oauth2PermissionGrants?$top=999' -tenantid $TenantFilter | ForEach-Object {
34+
$CurrentServicePrincipal = ($ServicePrincipals | Where-Object -Property id -EQ $_.clientId)
35+
[PSCustomObject]@{
36+
Name = $CurrentServicePrincipal.displayName
37+
ApplicationID = $CurrentServicePrincipal.appid
38+
ObjectID = $_.clientId
39+
Scope = ($_.scope -join ',')
40+
StartTime = $_.startTime
3241
}
3342
}
43+
$StatusCode = [HttpStatusCode]::OK
3444
} catch {
3545
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
3646
$StatusCode = [HttpStatusCode]::Forbidden

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListTenantAlignment.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ function Invoke-ListTenantAlignment {
7373
standardName = $ResolvedName
7474
complianceStatus = $_.ComplianceStatus
7575
compliant = $_.Compliant
76+
deviationStatus = $_.DeviationStatus
7677
licenseAvailable = $_.LicenseAvailable
7778
currentValue = $_.CurrentValue
7879
expectedValue = $_.ExpectedValue

0 commit comments

Comments
 (0)