Public/Get-InforcerAuditEvent.ps1
|
<# .SYNOPSIS Retrieves audit events from the Inforcer API. .DESCRIPTION POST /beta/auditEvents/search. When -DateFrom and -DateTo are omitted, uses a wide default range (10 years ago to now). When -EventType is not specified, uses all event types from the API (or fallback authentication, failedAuthentication). .PARAMETER EventType Event types to include. Omit for all types (tab-complete with supported event types). .PARAMETER DateFrom Start of date/time range (inclusive). Omit with DateTo = 10 years ago to now; if only DateTo set = 30 days before DateTo. .PARAMETER DateTo End of date/time range (inclusive). Omit with DateFrom = now (UTC). .PARAMETER PageSize Page size per API request. Default 100. .PARAMETER MaxResults Maximum events to return. 0 = no limit (default). .PARAMETER Format Raw (default). .PARAMETER OutputType PowerShellObject (default) or JsonObject. JSON output uses Depth 100. .EXAMPLE Get-InforcerAuditEvent .EXAMPLE Get-InforcerAuditEvent -DateFrom (Get-Date).AddDays(-7) -DateTo (Get-Date) .EXAMPLE Get-InforcerAuditEvent -EventType authentication,failedAuthentication -DateFrom $from -DateTo $to .EXAMPLE Get-InforcerAuditEvent -OutputType JsonObject Returns a JSON array string; output objects do not include a metadata property (flattened to top-level fields). .OUTPUTS PSObject or String (JSON array when -OutputType JsonObject) .LINK Connect-Inforcer #> function Get-InforcerAuditEvent { [CmdletBinding()] [OutputType([PSObject], [string])] param( [Parameter(Mandatory = $false)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $prefix = if ($wordToComplete) { $wordToComplete } else { '' } if ($prefix -match ',') { $prefix = ($prefix -split ',' | ForEach-Object { $_.Trim() })[-1] } $prefix = $prefix.Trim() # Inline list so completer never depends on script scope (avoids path completion fallback) $types = @( 'authentication', 'failedAuthentication', 'supportAccessInvoke', 'userGroupCreate', 'userGroupUpdate', 'userGroupDelete', 'userGroupMembershipModified', 'clientStatusChanged', 'clientCreated', 'salesAdminUpdated', 'clientAdminUpdated', 'sharedBaselinesManaged', 'alertRuleCreate', 'alertRuleUpdate', 'alertRuleDelete', 'apiKeyCreate', 'apiKeyDelete', 'apiKeyUsage', 'tenantUserCreate', 'tenantUserUpdate', 'tenantUserResetMfa', 'tenantUserResetPassword', 'tenantUserRevokedSessions', 'tenantUserGroupMembershipModified', 'tenantUserOffboardingQueued', 'tenantUserLicensesModified', 'tenantOnboard', 'tenantRefresh', 'tenantDelete', 'userCreate', 'userDelete', 'userResetPassword', 'userResetMfa', 'userToggleEnable', 'userAutoProvision', 'userToggleSso', 'tenantGroupCreate', 'tenantGroupUpdate', 'tenantGroupMembershipsModified', 'tenantGroupsDeployment', 'policiesDeployment', 'policiesRestore', 'policiesRename', 'policiesDelete', 'tenantAssessmentRun', 'tenantAssessmentSuccess', 'tenantAssessmentFailure', 'copilotAssessmentRun', 'copilotAssessmentSuccess', 'copilotAssessmentFailure', 'tenantLicenseUpdate', 'clientLicenseUpdate' ) $filterByPrefix = $prefix -and $prefix -notmatch '^[./\\]' if ($filterByPrefix) { $filtered = @($types | Where-Object { $_ -like "$prefix*" }) $exactMatch = $filtered | Where-Object { $_ -ceq $prefix } if ($exactMatch.Count -ne 1) { $types = $filtered } } foreach ($t in $types) { [Management.Automation.CompletionResult]::new($t, $t, [Management.Automation.CompletionResultType]::ParameterValue, $t) } })] [string[]]$EventType, [Parameter(Mandatory = $false)] [DateTime]$DateFrom, [Parameter(Mandatory = $false)] [DateTime]$DateTo, [Parameter(Mandatory = $false)] [int]$PageSize = 100, [Parameter(Mandatory = $false)] [int]$MaxResults = 0, [Parameter(Mandatory = $false)] [ValidateSet('Raw')] [string]$Format = 'Raw', [Parameter(Mandatory = $false)] [ValidateSet('PowerShellObject', 'JsonObject')] [string]$OutputType = 'PowerShellObject' ) if (-not (Test-InforcerSession)) { Write-Error -Message 'Not connected yet. Please run Connect-Inforcer first.' -ErrorId 'NotConnected' -Category ConnectionError return } # Resolve event types $eventTypes = @() if ($null -eq $EventType -or $EventType.Count -eq 0) { Write-Verbose 'Fetching all audit event types from API...' try { $eventTypes = @(Get-InforcerAuditEventType -ErrorAction SilentlyContinue) } catch { $eventTypes = @() } if ($eventTypes.Count -eq 0) { Write-Verbose 'Event types API failed or returned none; using authentication, failedAuthentication.' $eventTypes = @('authentication', 'failedAuthentication') } else { Write-Verbose "Using all $($eventTypes.Count) event type(s)." } } else { $eventTypes = @($EventType) } # Date range $dateFromVal = $DateFrom $dateToVal = $DateTo if ($dateFromVal -and -not $dateToVal) { $dateToVal = [DateTime]::UtcNow } if ($dateToVal -and -not $dateFromVal) { $dateFromVal = $dateToVal.AddDays(-30) } if (-not $dateFromVal -and -not $dateToVal) { $dateToVal = [DateTime]::UtcNow $dateFromVal = $dateToVal.AddYears(-10) } $dateFromStr = $dateFromVal.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') $dateToStr = $dateToVal.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ') $allItems = [System.Collections.ArrayList]::new() $hasLimit = $MaxResults -gt 0 $batchSize = 10 $typeBatches = @() for ($i = 0; $i -lt $eventTypes.Count; $i += $batchSize) { $end = [Math]::Min($i + $batchSize, $eventTypes.Count) $typeBatches += ,@($eventTypes[$i..($end - 1)]) } foreach ($batch in $typeBatches) { if ($hasLimit -and $allItems.Count -ge $MaxResults) { break } $continuationToken = $null do { $bodyObj = @{ eventTypes = @($batch) dateFrom = $dateFromStr dateTo = $dateToStr pageSize = $PageSize } if ($continuationToken) { $bodyObj['continuationToken'] = $continuationToken } $body = $bodyObj | ConvertTo-Json -Depth 100 -Compress Write-Verbose 'Searching audit events...' $response = Invoke-InforcerApiRequest -Endpoint '/beta/auditEvents/search' -Method POST -Body $body -OutputType PowerShellObject -PreserveStructure if ($null -eq $response) { break } # After -PreserveStructure, .data is already unwrapped but inner structure (items + continuationToken) is intact $root = $response $items = $null foreach ($propName in 'items', 'Items') { $prop = $root.PSObject.Properties[$propName] if ($prop -and $null -ne $prop.Value) { $items = $prop.Value; break } } if ($items) { foreach ($item in @($items)) { if ($item -is [PSObject]) { Add-InforcerPropertyAliases -InputObject $item -ObjectType AuditEvent | Out-Null [void]$allItems.Add($item) if ($hasLimit -and $allItems.Count -ge $MaxResults) { break } } } } $continuationToken = $null foreach ($tokenProp in 'continuationToken', 'ContinuationToken') { $tp = $root.PSObject.Properties[$tokenProp] if ($tp -and $tp.Value) { $continuationToken = $tp.Value; break } } if ($hasLimit -and $allItems.Count -ge $MaxResults) { break } } while ($continuationToken) } if ($OutputType -eq 'JsonObject') { $json = $allItems | ConvertTo-Json -Depth 100 return $json } else { $allItems | ForEach-Object { $_ } } } |