|
| 1 | +function Add-CippAuditLogCoverageManualEntry { |
| 2 | + <# |
| 3 | + .SYNOPSIS |
| 4 | + Bridge a manually-created audit log search into the V2 AuditLogCoverage ledger so the |
| 5 | + pipeline downloads and processes it automatically (Option B). |
| 6 | + .DESCRIPTION |
| 7 | + Manual searches live in the AuditLogSearches table, which the (now V2-only) pipeline no |
| 8 | + longer scans. When alert processing is requested for a manual search, this writes a ledger |
| 9 | + row keyed 'MANUAL-<searchId>' in State 'Created' so Start-AuditLogIngestionV2 / |
| 10 | + Push-AuditLogDownloadV2 poll, download and process it like any other search - it inherits |
| 11 | + retries, the orphan sweep, SearchStatus tracking and the coverage UI. |
| 12 | +
|
| 13 | + The RowKey prefix keeps these out of the window planner: Get-CippAuditLogPlannedWindows only |
| 14 | + considers 14-digit RowKeys and Get-CippAuditLogReconciliationWindows only 'RECON-*', so a |
| 15 | + 'MANUAL-*' row is never treated as a window, gap or reconciliation block. Type 'Manual' lets |
| 16 | + the UI exclude them from the window heatmap/charts. |
| 17 | +
|
| 18 | + Idempotent (UpsertMerge): re-queuing the same search resets State to 'Created' to reprocess. |
| 19 | + .PARAMETER TenantFilter |
| 20 | + Tenant default domain (becomes the ledger PartitionKey). |
| 21 | + .PARAMETER SearchId |
| 22 | + The Graph audit-log search id. |
| 23 | + .PARAMETER StartTime |
| 24 | + Search start (datetime / DateTimeOffset / ISO string). Stored as WindowStart. |
| 25 | + .PARAMETER EndTime |
| 26 | + Search end. Stored as WindowEnd. |
| 27 | + .PARAMETER SearchStatus |
| 28 | + Graph search status at creation (e.g. notStarted); refreshed on each poll. |
| 29 | + .PARAMETER TenantId |
| 30 | + Tenant customerId. Resolved from TenantFilter if not supplied. |
| 31 | + .FUNCTIONALITY |
| 32 | + Internal |
| 33 | + #> |
| 34 | + [CmdletBinding()] |
| 35 | + param( |
| 36 | + [Parameter(Mandatory = $true)][string]$TenantFilter, |
| 37 | + [Parameter(Mandatory = $true)][string]$SearchId, |
| 38 | + $StartTime, |
| 39 | + $EndTime, |
| 40 | + [string]$SearchStatus, |
| 41 | + [string]$TenantId |
| 42 | + ) |
| 43 | + |
| 44 | + try { |
| 45 | + if (-not $TenantId) { |
| 46 | + try { $TenantId = Get-Tenants -TenantFilter $TenantFilter | Select-Object -First 1 -ExpandProperty customerId } catch {} |
| 47 | + } |
| 48 | + |
| 49 | + $Now = (Get-Date).ToUniversalTime() |
| 50 | + $Ledger = Get-CippTable -TableName 'AuditLogCoverage' |
| 51 | + $Entity = @{ |
| 52 | + PartitionKey = [string]$TenantFilter |
| 53 | + RowKey = 'MANUAL-' + [string]$SearchId |
| 54 | + TenantId = [string]$TenantId |
| 55 | + Type = 'Manual' |
| 56 | + State = 'Created' |
| 57 | + SearchId = [string]$SearchId |
| 58 | + SearchStatus = [string]$SearchStatus |
| 59 | + Attempts = 0 |
| 60 | + RetryCount = 0 |
| 61 | + ThrottleCount = 0 |
| 62 | + CreatedUtc = $Now |
| 63 | + LastPolledUtc = $Now |
| 64 | + LastError = '' |
| 65 | + } |
| 66 | + if ($StartTime) { try { $Entity.WindowStart = ([datetimeoffset]$StartTime).UtcDateTime } catch {} } |
| 67 | + if ($EndTime) { try { $Entity.WindowEnd = ([datetimeoffset]$EndTime).UtcDateTime } catch {} } |
| 68 | + |
| 69 | + Add-CIPPAzDataTableEntity @Ledger -Entity $Entity -OperationType UpsertMerge |
| 70 | + Write-Information "AuditLogV2: bridged manual search $SearchId for $TenantFilter into coverage ledger (MANUAL-$SearchId)" |
| 71 | + } catch { |
| 72 | + Write-Information ('Add-CippAuditLogCoverageManualEntry error for {0} / {1}: {2}' -f $TenantFilter, $SearchId, $_.Exception.Message) |
| 73 | + } |
| 74 | +} |
0 commit comments