@@ -14,7 +14,8 @@ function Push-AuditLogSearchCreationV2 {
1414 limit, so on a 429 we stop and defer the current window AND all remaining queued windows to
1515 the next cycle (no Attempts increment - a cap is not a failure, so it never dead-letters).
1616 Other transient errors (UnknownError, 5xx, gateway) retry the individual window with backoff
17- and dead-letter at MaxAttempts. AuditingDisabled caches the tenant for 24h and stops.
17+ and dead-letter at MaxAttempts. AuditingDisabled and AccessDenied (token failure - e.g.
18+ AADSTS7000229 missing service principal) cache the tenant as disabled for 24h and stop.
1819
1920 Capping at 6/cycle keeps us well under the ~10 concurrent-search ceiling (they complete within
2021 the cycle and free slots). Oldest-first means gaps/backlog/reconciliation drain before the
@@ -77,15 +78,17 @@ function Push-AuditLogSearchCreationV2 {
7778 $Batch = @ ($Due | Select-Object - First $MaxPerCycle )
7879 }
7980
80- # 3) Create searches (no auto-retry). On 429, defer current + remaining to next cycle.
81+ # 3) Create searches (no auto-retry). On 429 or a tenant-level disable, defer current +
82+ # remaining to next cycle.
8183 $Bail = $false
84+ $BailReason = ' '
8285 foreach ($Row in $Batch ) {
8386 if ($Bail ) {
8487 # Deferred (not attempted): just set NextAttemptUtc, leave Attempts/State as Planned.
8588 Add-CIPPAzDataTableEntity @Ledger - Entity @ {
8689 PartitionKey = $TenantFilter ; RowKey = $Row.RowKey ; State = ' Planned'
8790 NextAttemptUtc = (Get-CippAuditLogNextAttempt - Attempts 1 )
88- ThrottleCount = ([int ]$Row.ThrottleCount + 1 ); LastError = ' Deferred: tenant search cap (429) ' ; LastErrorUtc = $Now
91+ ThrottleCount = ([int ]$Row.ThrottleCount + 1 ); LastError = $BailReason ; LastErrorUtc = $Now
8992 } - OperationType UpsertMerge
9093 continue
9194 }
@@ -105,23 +108,29 @@ function Push-AuditLogSearchCreationV2 {
105108 } elseif ($Result.Throttled ) {
106109 # 429 = tenant cap full. Defer this window (no Attempts bump - a cap isn't a failure) and bail.
107110 $Bail = $true
111+ $BailReason = ' Deferred: tenant search cap (429)'
108112 Add-CIPPAzDataTableEntity @Ledger - Entity @ {
109113 PartitionKey = $TenantFilter ; RowKey = $Row.RowKey ; State = ' Planned'
110114 NextAttemptUtc = (Get-CippAuditLogNextAttempt - Attempts 1 )
111115 ThrottleCount = ([int ]$Row.ThrottleCount + 1 ); LastError = ' Tenant search cap (429)' ; LastErrorUtc = $Now
112116 } - OperationType UpsertMerge
113117 Write-Information " AuditLogV2: 429 for $TenantFilter - deferring this + remaining windows to next cycle"
114- } elseif ($Result.Outcome -eq ' AuditingDisabled' ) {
118+ } elseif ($Result.Outcome -eq ' AuditingDisabled' -or $Result.Outcome -eq ' AccessDenied' ) {
119+ # AuditingDisabled = unified auditing off; AccessDenied = we can't get a token for the
120+ # tenant at all (e.g. missing service principal). Either way: disable for 24h and stop.
115121 $Bail = $true
122+ $BailReason = ' Deferred: tenant audit log collection disabled'
123+ $DisableStatus = if ($Result.Outcome -eq ' AccessDenied' ) { [string ]$Result.Status } else { ' AuditingDisabledTenant' }
124+ $LedgerError = if ($Result.Message ) { [string ]$Result.Message } else { $DisableStatus }
116125 try {
117126 $AuditDisabledTable = Get-CIPPTable - TableName ' AuditLogDisabledTenants'
118127 Add-CIPPAzDataTableEntity @AuditDisabledTable - Entity @ {
119128 PartitionKey = ' AuditDisabledTenant' ; RowKey = [string ]$TenantFilter ; TenantFilter = [string ]$TenantFilter
120- Status = ' AuditingDisabledTenant ' ; ExpiresAtUnix = [int64 ]([datetimeoffset ]::UtcNow.AddHours(24 ).ToUnixTimeSeconds())
129+ Status = $DisableStatus ; ExpiresAtUnix = [int64 ]([datetimeoffset ]::UtcNow.AddHours(24 ).ToUnixTimeSeconds())
121130 } - Force
122131 } catch {}
123- Add-CIPPAzDataTableEntity @Ledger - Entity @ { PartitionKey = $TenantFilter ; RowKey = $Row.RowKey ; State = ' Skipped' ; LastError = ' AuditingDisabledTenant ' ; LastErrorUtc = $Now } - OperationType UpsertMerge
124- Write-Information " AuditLogV2: auditing disabled for $TenantFilter ; skipping "
132+ Add-CIPPAzDataTableEntity @Ledger - Entity @ { PartitionKey = $TenantFilter ; RowKey = $Row.RowKey ; State = ' Skipped' ; LastError = $LedgerError ; LastErrorUtc = $Now } - OperationType UpsertMerge
133+ Write-Information " AuditLogV2: $DisableStatus for $TenantFilter ; disabled for 24h "
125134 } else {
126135 # Other transient: retry this window next cycle; dead-letter at cap.
127136 $RetryTotal = [int ]$Row.RetryCount + 1
0 commit comments