Skip to content

Commit 286d1bb

Browse files
authored
Merge pull request #914 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 9e1c375 + a0872fe commit 286d1bb

8 files changed

Lines changed: 97 additions & 58 deletions

File tree

Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdatePermissionsQueue.ps1

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ function Push-UpdatePermissionsQueue {
3030

3131
# Check for permission failures (excluding service principal creation failures)
3232
$AllResults = @($AppResults) + @($DelegatedResults)
33-
$PermissionFailures = $AllResults | Where-Object {
34-
$_ -like '*Failed*' -and
33+
$PermissionFailures = $AllResults | Where-Object {
34+
$_ -like '*Failed*' -and
3535
$_ -notlike '*Failed to create service principal*'
3636
}
3737

@@ -71,7 +71,8 @@ function Push-UpdatePermissionsQueue {
7171
}
7272
}
7373
} catch {
74-
Write-Information "Error updating permissions for $($Item.displayName)"
75-
Write-LogMessage -tenant $Item.defaultDomainName -tenantId $Item.customerId -message "Error updating permissions for $($Item.displayName) - $($_.Exception.Message)" -Sev 'Error' -API 'UpdatePermissionsQueue'
74+
Write-Information "Error updating permissions for $($Item.displayName): $($_.Exception.Message)"
75+
Write-Information $_.InvocationInfo.PositionMessage
76+
Write-LogMessage -tenant $Item.defaultDomainName -tenantId $Item.customerId -message "Error updating permissions for $($Item.displayName) - $($_.Exception.Message)" -Sev 'Error' -API 'UpdatePermissionsQueue' -LogData (Get-CippException -Exception $_)
7677
}
7778
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ function Invoke-ExecRestoreBackup {
99
param($Request, $TriggerMetadata)
1010

1111
$APIName = $Request.Params.CIPPEndpoint
12+
13+
# Types natively supported by Azure Table Storage — preserve these as-is
14+
$AzureTableTypes = @(
15+
[string], [int], [long], [double], [bool], [datetime], [guid], [byte[]]
16+
)
1217
$RestrictedTables = @('AccessRoleGroups', 'CustomRoles') # tables that require superadmin to restore
1318

1419
# Resolve the calling user's roles, including Entra group-based roles
@@ -60,7 +65,10 @@ function Invoke-ExecRestoreBackup {
6065
}
6166
$Table = Get-CippTable -tablename $_.table
6267
$ht2 = @{}
63-
$_.psobject.properties | ForEach-Object { $ht2[$_.Name] = [string]$_.Value }
68+
$_.psobject.properties | Where-Object { $_.Name -ne 'table' } | ForEach-Object {
69+
$val = $_.Value
70+
$ht2[$_.Name] = if ($null -ne $val -and $AzureTableTypes -contains $val.GetType()) { $val } else { [string]$val }
71+
}
6472
$Table.Entity = $ht2
6573
Add-AzDataTableEntity @Table -Force
6674
$RestoredCount++
@@ -86,7 +94,10 @@ function Invoke-ExecRestoreBackup {
8694
}
8795
$Table = Get-CippTable -tablename $line.table
8896
$ht2 = @{}
89-
$line.psobject.properties | ForEach-Object { $ht2[$_.Name] = [string]$_.Value }
97+
$line.psobject.properties | Where-Object { $_.Name -ne 'table' } | ForEach-Object {
98+
$val = $_.Value
99+
$ht2[$_.Name] = if ($null -ne $val -and $AzureTableTypes -contains $val.GetType()) { $val } else { [string]$val }
100+
}
90101
$Table.Entity = $ht2
91102
Add-AzDataTableEntity @Table -Force
92103
$RestoredCount++

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,61 +15,58 @@ function Invoke-ExecUpdateRefreshToken {
1515
# Handle refresh token update
1616
#make sure we get the latest authentication:
1717
$auth = Get-CIPPAuthentication
18+
$IsPartnerTenant = $env:TenantID -eq $Request.body.tenantId
19+
1820
if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') {
1921
$DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets'
2022
$Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'"
21-
22-
if ($env:TenantID -eq $Request.body.tenantId) {
23+
if ($IsPartnerTenant) {
2324
$Secret | Add-Member -MemberType NoteProperty -Name 'RefreshToken' -Value $Request.body.refreshtoken -Force
24-
# Set environment variable to make it immediately available
2525
Set-Item -Path env:RefreshToken -Value $Request.body.refreshtoken -Force
2626
} else {
27-
Write-Host "$($env:TenantID) does not match $($Request.body.tenantId)"
2827
$name = $Request.body.tenantId -replace '-', '_'
29-
$secret | Add-Member -MemberType NoteProperty -Name $name -Value $Request.body.refreshtoken -Force
30-
# Set environment variable to make it immediately available
28+
$Secret | Add-Member -MemberType NoteProperty -Name $name -Value $Request.body.refreshtoken -Force
3129
Set-Item -Path env:$name -Value $Request.body.refreshtoken -Force
3230
}
3331
Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force
3432
} else {
35-
if ($env:TenantID -eq $Request.body.tenantId) {
33+
if ($IsPartnerTenant) {
3634
Set-CippKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force)
37-
# Set environment variable to make it immediately available
3835
Set-Item -Path env:RefreshToken -Value $Request.body.refreshtoken -Force
39-
40-
# Trigger CPV refresh for partner tenant only
41-
try {
42-
$Queue = New-CippQueueEntry -Name 'Update Permissions - Partner Tenant' -TotalTasks 1
43-
$TenantBatch = @([PSCustomObject]@{
44-
defaultDomainName = 'PartnerTenant'
45-
customerId = $env:TenantID
46-
displayName = '*Partner Tenant'
47-
FunctionName = 'UpdatePermissionsQueue'
48-
QueueId = $Queue.RowKey
49-
})
50-
$InputObject = [PSCustomObject]@{
51-
OrchestratorName = 'UpdatePermissionsOrchestrator'
52-
Batch = @($TenantBatch)
53-
}
54-
Start-CIPPOrchestrator -InputObject $InputObject
55-
Write-Information 'Started permissions update orchestrator for Partner Tenant'
56-
} catch {
57-
Write-Warning "Failed to start permissions orchestrator: $($_.Exception.Message)"
58-
}
5936
} else {
60-
Write-Host "$($env:TenantID) does not match $($Request.body.tenantId) - we're adding a new secret for the tenant."
37+
Write-Information "$($env:TenantID) does not match $($Request.body.tenantId) - adding a new secret for the tenant."
6138
$name = $Request.body.tenantId
6239
try {
6340
Set-CippKeyVaultSecret -VaultName $kv -Name $name -SecretValue (ConvertTo-SecureString -String $Request.body.refreshtoken -AsPlainText -Force)
64-
# Set environment variable to make it immediately available
6541
Set-Item -Path env:$name -Value $Request.body.refreshtoken -Force
6642
} catch {
67-
Write-Host "Failed to set secret $name in KeyVault. $($_.Exception.Message)"
43+
Write-Information "Failed to set secret $name in KeyVault. $($_.Exception.Message)"
6844
throw $_
6945
}
7046
}
7147
}
7248

49+
if ($IsPartnerTenant) {
50+
try {
51+
$Queue = New-CippQueueEntry -Name 'Update Permissions - Partner Tenant' -TotalTasks 1
52+
$TenantBatch = @([PSCustomObject]@{
53+
defaultDomainName = 'PartnerTenant'
54+
customerId = $env:TenantID
55+
displayName = '*Partner Tenant'
56+
FunctionName = 'UpdatePermissionsQueue'
57+
QueueId = $Queue.RowKey
58+
})
59+
$InputObject = [PSCustomObject]@{
60+
OrchestratorName = 'UpdatePermissionsOrchestrator'
61+
Batch = @($TenantBatch)
62+
}
63+
Start-CIPPOrchestrator -InputObject $InputObject
64+
Write-Information 'Started permissions update orchestrator for Partner Tenant'
65+
} catch {
66+
Write-Warning "Failed to start permissions orchestrator: $($_.Exception.Message)"
67+
}
68+
}
69+
7370
if ($request.body.tenantId -eq $env:TenantID) {
7471
$TenantName = 'your partner tenant'
7572
} else {

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function Invoke-ExecIncidentsList {
1010
# Interact with query parameters or the body of the request.
1111
$TenantFilter = $Request.Query.tenantFilter
1212
$StartDate = $Request.Query.StartDate # YYYYMMDD or null
13-
$EndDate = $Request.Query.EndDate # YYYYMMDD or null
13+
$EndDate = $Request.Query.EndDate # YYYYMMDD or null
1414

1515
# Build OData $filter parts for Graph API (single-tenant path)
1616
$GraphFilterParts = [System.Collections.Generic.List[string]]::new()
@@ -88,11 +88,18 @@ function Invoke-ExecIncidentsList {
8888
}
8989
$Incidents = $Rows
9090
foreach ($incident in $Incidents) {
91-
$IncidentObj = $incident.Incident | ConvertFrom-Json
92-
# In-memory date filter for cached AllTenants data
93-
$created = [datetime]::Parse($IncidentObj.createdDateTime)
94-
if ($StartDate -and $created -lt [datetime]::ParseExact($StartDate, 'yyyyMMdd', $null)) { continue }
95-
if ($EndDate -and $created -ge [datetime]::ParseExact($EndDate, 'yyyyMMdd', $null).AddDays(1)) { continue }
91+
if ($incident.Incident -and (Test-Json -Json $incident.Incident)) {
92+
$IncidentObj = $incident.Incident | ConvertFrom-Json
93+
} else {
94+
continue
95+
}
96+
try {
97+
$created = [datetime]::Parse($IncidentObj.createdDateTime)
98+
if ($StartDate -and $created -lt [datetime]::ParseExact($StartDate, 'yyyyMMdd', $null)) { continue }
99+
if ($EndDate -and $created -ge [datetime]::ParseExact($EndDate, 'yyyyMMdd', $null).AddDays(1)) { continue }
100+
} catch {
101+
continue
102+
}
96103
[PSCustomObject]@{
97104
Tenant = $incident.Tenant
98105
Id = $IncidentObj.id

Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,14 @@ function New-CIPPCAPolicy {
219219
}
220220

221221
#for each of the locations, check if they exist, if not create them. These are in $JSONobj.LocationInfo
222+
$NewLocationsCreated = $false
222223
$LocationLookupTable = foreach ($locations in $JSONobj.LocationInfo) {
223224
if (!$locations) { continue }
224225
foreach ($location in $locations) {
225226
if (!$location.displayName) { continue }
226227
# Use cached named locations instead of fetching each time
227-
if ($Location.displayName -in $AllNamedLocations.displayName) {
228+
$locationExistsInCache = $Location.displayName -in $AllNamedLocations.displayName
229+
if ($locationExistsInCache) {
228230
$ExistingLocation = @($AllNamedLocations | Where-Object -Property displayName -EQ $Location.displayName)
229231
if ($ExistingLocation.Count -gt 1) {
230232
Write-Warning "Multiple named locations found with display name '$($Location.displayName)'. Using the first match: $($ExistingLocation[0].id). IDs found: $($ExistingLocation.id -join ', ')"
@@ -241,18 +243,21 @@ function New-CIPPCAPolicy {
241243
} catch {
242244
$ErrorMessage = Get-CippException -Exception $_
243245
Write-Information "Error updating named location: $($ErrorMessage | ConvertTo-Json -Depth 10 -Compress)"
244-
Write-Warning "Failed to update location $($location.displayName): $($ErrorMessage.NormalizedError)"
245-
Write-LogMessage -Tenant $TenantFilter -Headers $Headers -API $APIName -message "Failed to update existing Named Location: $($location.displayName). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage
246+
Write-LogMessage -Tenant $TenantFilter -Headers $Headers -API $APIName -message "Named Location '$($location.displayName)' (id: $($ExistingLocation.id)) could not be updated — it may have been deleted. Will attempt to create it. Error: $($ErrorMessage.NormalizedError)" -Sev 'Warn' -LogData $ErrorMessage
247+
$locationExistsInCache = $false
246248
}
247249
} else {
248250
Write-LogMessage -Tenant $TenantFilter -Headers $Headers -API $APIName -message "Matched a CA policy with the existing Named Location: $($location.displayName)" -Sev 'Info'
249251
}
250-
[pscustomobject]@{
251-
id = $ExistingLocation.id
252-
name = $ExistingLocation.displayName
253-
templateId = $location.id
252+
if ($locationExistsInCache) {
253+
[pscustomobject]@{
254+
id = $ExistingLocation.id
255+
name = $ExistingLocation.displayName
256+
templateId = $location.id
257+
}
254258
}
255-
} else {
259+
}
260+
if (-not $locationExistsInCache) {
256261
if ($location.countriesAndRegions) { $location.countriesAndRegions = @($location.countriesAndRegions) }
257262
$LocationBody = $location | Select-Object * -ExcludeProperty id
258263
Remove-ODataProperties -Object $LocationBody
@@ -280,6 +285,7 @@ function New-CIPPCAPolicy {
280285
if (!$LocationRequest -or !$LocationRequest.id) {
281286
Write-Warning "Location created but could not verify availability after $MaxRetryCount attempts. Proceeding anyway."
282287
}
288+
$NewLocationsCreated = $true
283289
Write-LogMessage -Tenant $TenantFilter -Headers $Headers -API $APIName -message "Created new Named Location: $($location.displayName)" -Sev 'Info'
284290
} catch {
285291
$ErrorMessage = Get-CippException -Exception $_
@@ -445,7 +451,7 @@ function New-CIPPCAPolicy {
445451
# Preserve any exclusion groups named "Vacation Exclusion - <PolicyDisplayName>" from existing policy
446452
try {
447453
$ExistingVacationGroup = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=startsWith(displayName,'Vacation Exclusion')&`$select=id,displayName&`$top=999&`$count=true" -ComplexFilter -tenantid $TenantFilter -asApp $true |
448-
Where-Object { $CheckExisting.conditions.users.excludeGroups -contains $_.id }
454+
Where-Object { $CheckExisting.conditions.users.excludeGroups -contains $_.id }
449455
if ($ExistingVacationGroup) {
450456
if (-not ($JSONobj.conditions.users.PSObject.Properties.Name -contains 'excludeGroups')) {
451457
$JSONobj.conditions.users | Add-Member -NotePropertyName 'excludeGroups' -NotePropertyValue @() -Force
@@ -475,10 +481,24 @@ function New-CIPPCAPolicy {
475481
}
476482
} else {
477483
Write-Information 'Creating new policy'
478-
if ($JSOObj.GrantControls.authenticationStrength.policyType -or $JSONobj.$JSONobj.LocationInfo) {
479-
Start-Sleep 3
480-
}
481-
$null = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $TenantFilter -type POST -body $RawJSON -asApp $true -ScheduleRetry $true
484+
$PolicyCreateAttempt = 0
485+
$PolicyCreateMaxAttempts = 2
486+
$PolicyCreated = $false
487+
do {
488+
$PolicyCreateAttempt++
489+
try {
490+
$null = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $TenantFilter -type POST -body $RawJSON -asApp $true -ScheduleRetry $true
491+
$PolicyCreated = $true
492+
} catch {
493+
$PolicyCreateError = Get-CippException -Exception $_
494+
if ($PolicyCreateError.NormalizedError -match '1040' -and $NewLocationsCreated -and $PolicyCreateAttempt -lt $PolicyCreateMaxAttempts) {
495+
Write-Information "Named location not yet propagated (attempt $PolicyCreateAttempt/$PolicyCreateMaxAttempts), retrying in 5 seconds..."
496+
Start-Sleep -Seconds 5
497+
} else {
498+
throw $_
499+
}
500+
}
501+
} while (-not $PolicyCreated -and $PolicyCreateAttempt -lt $PolicyCreateMaxAttempts)
482502
Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message "Added Conditional Access Policy $($JSONobj.displayName)" -Sev 'Info'
483503
return "Created policy $($JSONobj.displayName) for $TenantFilter"
484504
}

Modules/CIPPCore/Public/New-CIPPDbRequest.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ function New-CIPPDbRequest {
3232

3333
$Tenant = Get-Tenants -TenantFilter $TenantFilter | Select-Object -ExpandProperty defaultDomainName
3434
if (-not $Tenant) {
35+
if ($TenantFilter -eq $env:TenantID) {
36+
return $false
37+
}
3538
throw "Tenant '$TenantFilter' not found"
3639
}
3740
$SafeTenantFilter = ConvertTo-CIPPODataFilterValue -Value $Tenant -Type String

host.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"distributedTracingEnabled": false,
1717
"version": "None"
1818
},
19-
"defaultVersion": "10.3.0",
19+
"defaultVersion": "10.3.1",
2020
"versionMatchStrategy": "Strict",
2121
"versionFailureStrategy": "Fail"
2222
}

version_latest.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
10.3.0
1+
10.3.1

0 commit comments

Comments
 (0)