Public/Add-OSLogPSBulk.ps1
function Add-OSLogPSBulk { <# .SYNOPSIS Adds PowerShell log to a log_ps_* data stream using the bulk API for improved performance. .DESCRIPTION Specialized function for logging data from various PowerShell scripts. Success returns nothing. Uses the bulk API for improved performance. Use this over Add-OSLogPS when you are less concerned with log reliabity, and more concerned with performance (such as with extremely verbose logs). Use a trap{} in your script to improve reliability of Add-OSLogPSBulk .PARAMETER Index Name of the PowerShell index to add to. Must be log_ps_misc OR follow format: log_ps_{SCRIPT NAME}_{OPTIONAL HOSTNAME}-{OPTIONAL EXTRA INFO} .PARAMETER Logs Array of hashtables containing the logs. Requires keys: - LogLevel - @timestamp (Containing the timestamp of when the log occurred) .PARAMETER DisableLocalLog Use to disable using the local LogFile option. Disabling will speed up the function. .PARAMETER LogFile Path to a local log file to save a copy of what's sent to OpenSearch. Defaults to: $PSScriptRoot/Logs/$ScriptName_OpenSearch_yyyy-MM-dd.json .PARAMETER OpType Operation to perform on the API. This will default to index, and usually that is fine. Data streams need 'create' .PARAMETER UploadLimit Break up upload to this many files per attempt. Max 4999. Break up upload to this many files per attempt. Max 4999. Sometimes necessary if individual documents are large. .PARAMETER Credential PSCredential for basic authentication to OpenSearch. .PARAMETER Certificate User certificate for certificate authentication to OpenSearch. .PARAMETER OpenSearchURL URL(s) to OpenSearch instance. Do not include any path or api endpoint. .EXAMPLE # In case of terminating error, upload existing logs trap { if ($LogList.Count -gt 0){ $Params = @{ 'Index' = 'log_ps_example' 'OpType' = 'Create' 'Logs' = $LogList 'ErrorAction' = 'Continue' } Add-OSLogPSBulk @Params } } #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Index, [Parameter(Mandatory)] [System.Collections.Generic.List[Hashtable]]$Logs, [switch]$DisableLocalLog, [string]$LogFile, [ValidateSet('create','delete','index','update')] [string]$OpType='index', [Int64]$UploadLimit=4999, [System.Management.Automation.Credential()] [PSCredential]$Credential=[PSCredential]::Empty, [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, $OpenSearchURL ) # Only lowercase index names are allowed $Index = $Index.ToLower() # Verify format of IndexName if ($Index -notmatch 'log_ps_'){ throw [System.ArgumentException] 'IndexName must be: log_ps_misc OR match the format: log_ps_{SCRIPT NAME}_{OPTIONAL HOSTNAME}-{OPTIONAL EXTRA INFO}' } # Script name is used for OpenSearch log and path to save local copy of log $ScriptName = $(Get-PSCallStack | Where-Object {$_.Command -match '.ps1'})[0].Command if ('' -eq $LogFile){ $LogFile = "$global:PSScriptRoot\Logs\$($ScriptName.replace('.ps1',''))_OpenSearch_$(Get-Date -Format yyyy-MM-dd).json" } # Build the request $FieldNames = @{} foreach ($LogEntry in $Logs){ # Validate data if ($LogEntry.LogLevel -notin @('Trace', 'Verbose', 'Information', 'Warning', 'Error', 'Critical')){ throw "LogLevel must be one of the following options: Trace, Verbose, Information, Warning, Error, Critical`nYour provided level: $($LogEntry.LogLevel)" } if ($null -eq $LogEntry.'@timestamp'){ throw "Each log must have a key named '@timestamp' with the value being the timestamp" } foreach ($key in $LogEntry.Keys){ if ($key -ne '@timestamp' -and $key -ne 'LogLevel'){ $FieldNames.$key = 'value' } } # Add auto generated fields $LogEntry.'Hostname' = $env:COMPUTERNAME $LogEntry.'PoSH.Script' = $ScriptName $LogEntry.'@timestamp' = $(Get-Date) } # Validate fild naming standard Confirm-OSFieldNamingStandard -FieldNames $FieldNames $Logs = $Logs.ToArray() # Add log content to local log file if ($False -eq $DisableLocalLog){ if (-not (Test-Path $LogFile)){ # Redirect to $null, otherwise if there's no other return response it returns the Path object to the log New-Item -Path $LogFile -Force > $null $LogEntries = $Logs } else { [Array]$LogEntries = Get-Content $LogFile | ConvertFrom-Json -Depth 100 $LogEntries += $Logs } $LogEntries | ConvertTo-Json -Depth 100 -AsArray | Out-File -FilePath $LogFile } $Response = Import-OSAllBulkDocument -Index $Index -Documents $Logs -OpType $OpType -UploadLimit $UploadLimit -Credential $Credential -Certificate $Certificate -OpenSearchURL $OpenSearchURL if ($Response -eq $true -or $null -eq $Response){ return } else { throw $Response } } Export-ModuleMember -Function Add-OSLogPSBulk |