From 18d64be1339def7fa5090e82cf4c7b34c21633df Mon Sep 17 00:00:00 2001 From: Eric H Date: Tue, 8 Mar 2022 09:12:04 -0700 Subject: [PATCH 1/3] Dev 1.2.4 (#83) * Update Get-LrtAzSecurityAlerts.ps1 Correct pagination behavior to prevent data return error based on endpoint restriction on number of returned results. Corrected behavior of -top when applied without any other filter criteria. * Update Invoke-AzureSecEventSync.ps1 Remove use of FileBeat, shifted integration to leverage Webhook Beat with SDP. * Update Invoke-AzureSecEventSync.ps1 Mature parsing content. * Update Invoke-AzureSecEventSync.ps1 Mature collection and incorporate additional metadata mapping. * Update Invoke-AzureSecEventSync.ps1 Code cleanup, reduce complexity. * Update Get-LrAgentsAccepted.ps1 Set default behavior to return only those that are active. Still supports returning all results if requested. * Update New-LrHost.ps1 Update field submitted for entity name. API requires the fullName in place of the Name. * Update Update-LrHost.ps1 Update field submitted for entity name. API requires the fullName in place of the Name. Addressed non-persistent setting carry over for records that have eventlogcredentials set on existing record. * Create Get-LrAgentsPending.ps1 New cmdlet to support retrieving pending system monitor agents. * Add PassThru and Force switch parameters Force switch will force set the case ownership when provided this flag, to ensure the requested owner is added as a collaborator in the event that they are not an existing collaborator. Added PassThru to align to best practices. * Update Get-LrCases.ps1 Adds new capability for retrieving cases based on tags, whereby you can select to return cases with all tags requested, or any of the tags requested. Note with any tags, if no tags out of the tags listed as assigned to the case(s) then no results will be returned. At least one of the requested tags is required to be present. * Create Update-LrIdentity.ps1 Resolve missing cmdlet from the TrueIdentity admin API endpoints. * Update Get-LrHosts.ps1 Update Get-LrHosts to support working with specific child entity records. Reference the inability to lookup Hosts based on Parent/Child entity record name, only based on Name (includes Parent and multiple Children.) * Update Update-LrHost.ps1 Fix spacing * Update Get-LrList.ps1 Translate int32 id representing a log source, or log source type, to also include the meaningful name for the specific item. * Update Get-LrAlarms.ps1 Fix pagination, add max-pages capability, fix CaseAssociation and Notification param options. * Add pipeline param options for Alarms API --- .../Invoke-AzureSecEventSync.ps1 | 744 +++++++++++++----- .../Security/Get-LrtAzSecurityAlerts.ps1 | 38 +- .../Admin/Agents/Get-LrAgentsAccepted.ps1 | 2 +- .../Admin/Agents/Get-LrAgentsPending.ps1 | 331 ++++++++ .../LogRhythm/Admin/Hosts/Get-LrHosts.ps1 | 22 +- .../LogRhythm/Admin/Hosts/New-LrHost.ps1 | 9 +- .../LogRhythm/Admin/Hosts/Update-LrHost.ps1 | 18 +- .../Admin/Identities/Update-LrIdentity.ps1 | 254 ++++++ .../LogRhythm/Admin/Lists/Get-LrList.ps1 | 17 + .../LogRhythm/Alarms/Add-LrAlarmComment.ps1 | 4 +- src/Public/LogRhythm/Alarms/Get-LrAlarm.ps1 | 12 +- .../LogRhythm/Alarms/Get-LrAlarmEvents.ps1 | 11 +- src/Public/LogRhythm/Alarms/Get-LrAlarms.ps1 | 69 +- .../LogRhythm/Case/General/Get-LrCases.ps1 | 101 ++- .../Case/General/Update-LrCaseOwner.ps1 | 33 +- 15 files changed, 1405 insertions(+), 260 deletions(-) create mode 100644 src/Public/LogRhythm/Admin/Agents/Get-LrAgentsPending.ps1 create mode 100644 src/Public/LogRhythm/Admin/Identities/Update-LrIdentity.ps1 diff --git a/examples/Azure/GraphAPI/SecurityEvents_to_OC/Invoke-AzureSecEventSync.ps1 b/examples/Azure/GraphAPI/SecurityEvents_to_OC/Invoke-AzureSecEventSync.ps1 index dfe5d22..84e0d0b 100644 --- a/examples/Azure/GraphAPI/SecurityEvents_to_OC/Invoke-AzureSecEventSync.ps1 +++ b/examples/Azure/GraphAPI/SecurityEvents_to_OC/Invoke-AzureSecEventSync.ps1 @@ -11,7 +11,16 @@ $CleanupDate = (Get-Date).AddDays(-90).Date # OpenCollector Webhook Endpoint -$OCEndpoint = 'http://172.17.5.20:8080/webhook' +$OCEndpoint = 'http://172.17.5.20:8085/webhook' + +# Enable Azure Alert Providers +$AZAlertProviders = [List[string]]::new() +$AZAlertProviders.add('AzureATP') +$AZAlertProviders.add('AzureSecurityCenter') +$AZAlertProviders.add('MCAS') +$AZAlertProviders.add('AzureADIdentityProtection') +$AZAlertProviders.add('DefenderATP') +$AZAlertProviders.add('AzureSentinel') ##### @@ -33,215 +42,578 @@ if (!(Test-Path $SecEventSyncLogPath -PathType Leaf)) { # Load in Security Events Log $SecEventLogs = Import-Csv -Path $SecEventSyncLogPath -# Begin Section - AzureATP -$AzureATP_SecEvents = Get-LrtAzSecurityAlerts -AzureATP -Status 'newAlert' -$AzureATP_LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like "AzureATP" - - -# Loop through results and proceed to process identified new events -ForEach ($AZAtpSecurityEvent in $AzureATP_SecEvents) { - if ($AzureATP_LoggedEvents.Id -notcontains $AZAtpSecurityEvent.Id) { - # New Event - # Establish Log Entry - $SecEvent = [PSCustomObject]@{ - log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) - event_timestamp = $AZAtpSecurityEvent.createdDateTime - type = "AzureATP" - id = $AZAtpSecurityEvent.id - azureTenantId = $AZAtpSecurityEvent.azureTenantId - severity = $AZAtpSecurityEvent.severity - } +ForEach ($AZAlertProvider in $AZAlertProviders) { + write-host "Processing: $AZAlertProvider" + switch ($AZAlertProvider) { + 'AzureATP' { $SecEvents = Get-LrtAzSecurityAlerts -AzureATP -Status 'newAlert' } + 'AzureSecurityCenter' { $SecEvents = Get-LrtAzSecurityAlerts -AzureSecurityCenter -Status 'newAlert' } + 'MCAS' { $SecEvents = Get-LrtAzSecurityAlerts -MCAS -Status 'newAlert' } + 'AzureADIdentityProtection' { $SecEvents = Get-LrtAzSecurityAlerts -AzureADIdentityProtection -Status 'newAlert' } + 'DefenderATP' { $SecEvents = Get-LrtAzSecurityAlerts -DefenderATP -Status 'newAlert' } + 'AzureSentinel' { $SecEvents = Get-LrtAzSecurityAlerts -AzureSentinel -Status 'newAlert' } + } - # Write out JSON event for FileBeat - Try { - Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($AZAtpSecurityEvent | ConvertTo-Json -Depth 50 -Compress) - - # Record Log Entry + $LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like $AZAlertProvider + + ForEach ($SecEvent in $SecEvents) { + if ($LoggedEvents.Id -notcontains $SecEvent.Id) { + # Establish log entry. + $LoggedEvent = [PSCustomObject]@{ + log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) + event_timestamp = $SecEvent.createdDateTime + type = $AZAlertProvider + id = $SecEvent.id + azureTenantId = $SecEvent.azureTenantId + severity = $SecEvent.severity + } + + # Global alert parsing + $OCLog = [PSCustomObject]@{ + tag1 = $SecEvent.vendorInformation.provider + tag2 = $SecEvent.category + object = $SecEvent.vendorInformation.provider + severity = $SecEvent.severity + policy = $SecEvent.category + vmid = $SecEvent.azureSubscriptionId + serialnumber = $SecEvent.azureTenantId + session = $SecEvent.id + reason = $SecEvent.description + status = $SecEvent.status + threatname = $SecEvent.title + # These properties change as the objecttype shifts from BaseAlert to the other alert elements + # The updates to these metadata values align to the same usecase and purpose of the values set on the BaseAlert. + objecttype = 'BaseAlert' + size = $SecEvent.riskScore + vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/alert?view=graph-rest-1.0' + + dname = $null + domainorigin = $null + domainimpacted = $null + account = $null + action = $null + amount = $null + dip = $null + dnatip = $null + dport = $null + hash = $null + login = $null + objectname = $null + process = $null + processid = $null + parentprocessname = $null + parentprocesspath = $null + parentprocessid = $null + quantity = $null + sessiontype = $null + sip = $null + snatip = $null + sname = $null + subject = $null + sport = $null + threatid = $null + url = $null + useragent = $null + "timestamp.iso8601" = $('{0:yyyy-MM-ddTHH:mm:ssZ}' -f $($([DateTime]$SecEvent.createdDateTime).ToUniversalTime())) + original_message = $SecEvent + whsdp = $true + fullyqualifiedbeatname = "webhookbeat_AzureGraph-$($SecEvent.vendorInformation.provider.replace(' ',''))" + } + # (get-date -Format yyyy-MM-ddTHH:mm:ssZ) Try { - $SecEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null } Catch { Write-Host $_ } - } Catch { - Write-Host $_ - } - } -} -# End Section - AzureATP - -# Begin Section - AzureSecurityCenter -$AzureSecurityCenter_SecEvents = Get-LrtAzSecurityAlerts -AzureSecurityCenter -Status 'newAlert' -$AzureSecurityCenter_LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like "AzureSecurityCenter" - -# Loop through results and proceed to process identified new events -ForEach ($AzSecCenSecurityEvent in $AzureSecurityCenter_SecEvents) { - if ($AzureSecurityCenter_LoggedEvents.Id -notcontains $AzSecCenSecurityEvent.Id) { - # New Event - # Establish Log Entry - $SecEvent = [PSCustomObject]@{ - log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) - event_timestamp = $AzSecCenSecurityEvent.createdDateTime - type = "AzureSecurityCenter" - id = $AzSecCenSecurityEvent.id - azureTenantId = $AzSecCenSecurityEvent.azureTenantId - severity = $AzSecCenSecurityEvent.severity - } + if ($null -ne $SecEvent.cloudAppStates) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.cloudAppStates.count + $OCLog.objecttype = 'CloudAppState' + ForEach ($CloudAppState in $SecEvent.cloudAppStates) { + $EventCurrent++ + $OCLog.amount = $EventCurrent - # Write out JSON event for FileBeat - Try { - Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($AzSecCenSecurityEvent | ConvertTo-Json -Depth 50 -Compress) - - # Record Log Entry - Try { - $SecEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append - } Catch { - Write-Host $_ + # Capture Destination Service IP + if ($CloudAppState.destinationServiceIp) { + $OCLog.dip = $CloudAppState.destinationServiceIp + } + + # Capture DestinationServiceName + if ($CloudAppState.destinationServiceName) { + $OCLog.process = $CloudAppState.destinationServiceName + } + + # Capture CloudAppState Risk Score + if ($CloudAppState.riskScore) { + $OCLog.size = $CloudAppState.riskScore + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/cloudappsecuritystate?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.dip = $null + $OCLog.process = $null + $OCLog.size = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null } - } Catch { - Write-Host $_ - } - } -} -# End Section - AzureSecurityCenter - - -# Begin Section - MCAS -$MCAS_SecEvents = Get-LrtAzSecurityAlerts -MCAS -Status 'newAlert' -$MCAS_LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like "MCAS" - -# Loop through results and proceed to process identified new events -ForEach ($MCASSecurityEvent in $MCAS_SecEvents) { - if ($MCAS_LoggedEvents.Id -notcontains $MCASSecurityEvent.Id) { - # New Event - # Establish Log Entry - $SecEvent = [PSCustomObject]@{ - log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) - event_timestamp = $MCASSecurityEvent.createdDateTime - type = "MCAS" - id = $MCASSecurityEvent.id - azureTenantId = $MCASSecurityEvent.azureTenantId - severity = $MCASSecurityEvent.severity - } - $MCASSecurityEvent | Add-Member -MemberType NoteProperty -Name "tag" -Value "AZURE_MCAS" -Force + if ($SecEvent.sourceMaterials) { + $EventCurrent = 0 + $OCLog.quantity = $($SecEvent.sourceMaterials | Sort-Object -Unique).count + $OCLog.objecttype = 'SourceMaterials' + ForEach ($SourceMaterial in $($SecEvent.sourceMaterials | Sort-Object -Unique)) { + $EventCurrent++ + $OCLog.amount = $EventCurrent - # Write out JSON event for FileBeat - Try { - Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($MCASSecurityEvent | ConvertTo-Json -Depth 50 -Compress) - Try { - $SecEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append - } Catch { - Write-Host $_ + $OCLog.url = $SourceMaterial + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/alert?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.vendorinfo = $null + $OCLog.url = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null } - } Catch { - Write-Host $_ - } - } -} -# End Section - MCAS - -# Begin Section - AzureADIdentityProtection -$AzureADIdentityProtection_SecEvents = Get-LrtAzSecurityAlerts -AzureADIdentityProtection -Status 'newAlert' -$AzureADIdentityProtection_LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like "AzureADIdentityProtection" - -# Loop through results and proceed to process identified new events -ForEach ($AZADIdProtSecurityEvent in $AzureADIdentityProtection_SecEvents) { - if ($AzureADIdentityProtection_LoggedEvents.Id -notcontains $AZADIdProtSecurityEvent.Id) { - # New Event - # Establish Log Entry - $SecEvent = [PSCustomObject]@{ - log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) - event_timestamp = $AZADIdProtSecurityEvent.createdDateTime - type = "AzureADIdentityProtection" - id = $AZADIdProtSecurityEvent.id - azureTenantId = $AZADIdProtSecurityEvent.azureTenantId - severity = $AZADIdProtSecurityEvent.severity - } - # Write out JSON event for FileBeat - Try { - Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($AZADIdProtSecurityEvent | ConvertTo-Json -Depth 50 -Compress) + # File States + if ($null -ne $SecEvent.fileStates) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.fileStates.count + $OCLog.objecttype = 'FileState' + ForEach ($FileState in $SecEvent.fileStates) { + $EventCurrent++ + $OCLog.amount = $EventCurrent - # Record Log Entry - Try { - $SecEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append - } Catch { - Write-Host "Unable to append to file: $SecEventSyncLogPath" + # Capture File Names + if ($FileState.fileHash.hashValue) { + $OCLog.hash = $FileState.fileHash.hashValue + } + + # Capture File Hashes + if ($FileState.fileHash.hashType) { + $OCLog.objectname = $FileState.fileHash.hashType + } + + if ($FileState.name) { + $OCLog.process = $FileState.name + } + + if ($FileState.riskScore) { + $OCLog.size = $FileState.riskScore + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/filesecuritystate?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.process = $null + $OCLog.hash = $null + $OCLog.size = $null + $OCLog.objectname = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null + } + + # Process States + if ($null -ne $SecEvent.processes) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.processes.count + $OCLog.objecttype = 'Process' + ForEach ($Process in $SecEvent.processes) { + $EventCurrent++ + $OCLog.amount = $EventCurrent + + # Capture File Names + if ($Process.accountName) { + $OCLog.login = $Process.accountName + } + + # Capture File Hashes + if ($Process.name) { + $OCLog.process = $Process.name + } + + if ($Process.processId) { + $OCLog.processid = $Process.processId + } + + if ($Process.commandLine) { + $OCLog.process = $Process.commandLine + } + + if ($Process.parentProcessName) { + $OCLog.parentprocessname = $Process.parentProcessName + } + + if ($Process.parentProcessId) { + $OCLog.parentprocessid = $Process.parentProcessId + } + + if ($Process.fileHash.hashValue) { + $OCLog.hash = $Process.fileHash.hashValue + } + + if ($Process.fileHash.hashType) { + $OCLog.subject = $Process.fileHash.hashType + } + + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/process?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.process = $null + $OCLog.hash = $null + $OCLog.size = $null + $OCLog.objectname = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null + } + + + # Security Resources + if ($null -ne $SecEvent.securityResources) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.securityResources.count + $OCLog.objecttype = 'SecurityResource' + ForEach ($SecResource in $SecEvent.securityResources) { + $EventCurrent++ + $OCLog.amount = $EventCurrent + + if ($SecResource.resource) { + $OCLog.objectname = $SecResource.resource + } + + if ($SecResource.resourceType) { + switch ($SecResource.resourceType) { + 1 {$OCLog.subject = "The resource was attacked in the alert."} + 2 {$OCLog.subject = "The resource is related to the alert, though not directly attacked."} + 'attacked' {$OCLog.subject = "The resource was attacked in the alert."} + 'related' {$OCLog.subject = "The resource is related to the alert, though not directly attacked."} + default { + $OCLog.subject = "The resource has not been defined as being attacked or related to the attack." + } + } + + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/securityresource?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + + $OCLog.objectname = $null + $OCLog.subject = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null + } + + + + # NetworkConnections + if ($null -ne $SecEvent.networkConnections) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.networkConnections.count + $OCLog.objecttype = 'NetworkConnection' + ForEach ($NetConn in $SecEvent.networkConnections) { + $EventCurrent++ + $OCLog.amount = $EventCurrent + + if ($NetConn.sourceAddress) { + $OCLog.sip = $NetConn.sourceAddress + } + + if ($NetConn.destinationAddress) { + $OCLog.dip = $NetConn.destinationAddress + } + + if ($NetConn.sourcePort) { + $OCLog.sport = $NetConn.sourceAddress + } + + if ($NetConn.destinationPort) { + $OCLog.dport = $NetConn.destinationPort + } + + if ($NetConn.natSourceAddress) { + $OCLog.snatip = $NetConn.natSourceAddress + } + + if ($NetConn.natDestinationAddress) { + $OCLog.dnatip = $NetConn.natDestinationAddress + } + + if ($NetConn.destinationUrl) { + $OCLog.url = $NetCon.destinationUrl + } + + if ($NetConn.riskScore) { + $OCLog.size = $NetConn.riskScore + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/networkconnection?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.sip = $null + $OCLog.dip = $null + $OCLog.hash = $null + $OCLog.url = $null + $OCLog.dnatip = $null + $OCLog.snatip = $null + $OCLog.dport = $null + $OCLog.sport = $null + $OCLog.size = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null + } + + + + if ($null -ne $SecEvent.malwareStates) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.malwareStates.count + $OCLog.objecttype = 'MalwareState' + ForEach ($MalwareState in $SecEvent.malwareStates) { + $EventCurrent++ + $OCLog.amount = $EventCurrent + + # Capture Malware Name as ThreatID + if ($MalwareState.name) { + $OCLog.threatid = $MalwareState.name + } + + if ($MalwareState.category) { + $OCLog.objectname = $MalwareState.category + } + + if ($MalwareStates.family) { + $OCLog.process = $MalwareState.family + } + + if ($MalwareStates.severity) { + $OCLog.subject = $MalwareStates.severity + } + + if ($MalwareStates.wasRunning) { + $OCLog.sessiontype = "Malware reported as running at the time of detection." + } else { + $OCLog.sessiontype = "Malware reported as not running at the time of detection." + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/malwarestate?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.threatid = $null + $OCLog.process = $null + $OCLog.subject = $null + $OCLog.objectname = $null + $OCLog.sessiontype = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null + } + + + if ($null -ne $SecEvent.hostStates) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.hostStates.count + ForEach ($HostState in $SecEvent.hostStates) { + $EventCurrent++ + $OCLog.amount = $EventCurrent + $OCLog.objecttype = 'HostState' + + if ($HostState.fqdn) { + $OCLog.sname = $HostState.fqdn + } elseif ($HostState.netBiosName) { + Try { + $netBNtoIP = [IPAddress] $HostState.netBiosName + if ($null -eq $HostState.privateIpAddress) { + $OCLog.sip = $netBNtoIP.IPAddressToString + } + } Catch { + $OCLog.sname = $HostState.netBiosName + } + + } + + if ($HostState.isAzureAdJoined) { + $OCLog.sessiontype = "AzureAdJoined" + } + + if ($HostState.isAzureAdRegistered) { + $OCLog.objectname = "AzureAdRegistered" + } + + if ($HostState.isHybridAzureDomainJoined) { + $OCLog.subject = "HybridAzureDomainJoined" + } + + if ($HostState.os) { + $OCLog.useragent = $HostState.os + } + + if ($HostState.privateIpAddress) { + $OCLog.sip = $HostState.privateIpAddress + } + + if ($HostState.publicIpAddress) { + $OCLog.snatip = $HostState.publicIpAddress + } + + if ($HostState.riskScore) { + $OCLog.size = $HostState.riskScore + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/hostsecuritystate?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + $OCLog.size = $null + $OCLog.snatip = $null + $OCLog.sip = $null + $OCLog.useragent = $null + $OCLog.sname = $null + $OCLog.subject = $null + $OCLog.objectname = $null + $OCLog.sessiontype = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null } - } Catch { - Write-Host $_ - } - } -} -# End Section - AzureADIdentityProtection - -# Begin Section - AzureSentinel -$AzureSentinel_SecEvents = Get-LrtAzSecurityAlerts -AzureSentinel -Status 'newAlert' -$AzureSentinel_LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like "AzureSentinel" - -# Loop through results and proceed to process identified new events -ForEach ($AZSentSecurityEvent in $AzureSentinel_SecEvents) { - if ($AzureSentinel_LoggedEvents.Id -notcontains $AZSentSecurityEvent.Id) { - # New Event - # Establish Log Entry - $SecEvent = [PSCustomObject]@{ - log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) - event_timestamp = $AZSentSecurityEvent.createdDateTime - type = "AzureSentinel" - id = $AZSentSecurityEvent.id - azureTenantId = $AZSentSecurityEvent.azureTenantId - severity = $AZSentSecurityEvent.severity - } - # Write out JSON event for FileBeat - Try { - Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($AZSentSecurityEvent | ConvertTo-Json -Depth 50 -Compress) + # Submit one log for each UserState entry + if ($null -ne $SecEvent.userStates) { + $EventCurrent = 0 + $OCLog.quantity = $SecEvent.userStates.count + $OCLog.objecttype = 'UserStates' + ForEach ($UserState in $SecEvent.userStates) { + $EventCurrent++ + $OCLog.amount = $EventCurrent + + # Preference to userPrincipalName as this will be username+domainName + if ($UserState.userPrincipalName) { + $OCLog.login = $UserState.userPrincipalName + } elseif ($UserState.accountName) { + $OCLog.login = $UserState.accountName + } + + if ($UserState.aadUserId) { + $OCLog.subject = $UserState.aadUserId + } + + if ($UserState.logonIp) { + $OCLog.sip = $UserState.logonIp + } + + if ($UserState.isVpn) { + $OCLog.sessiontype = "VPN" + } elseif ($UserState.logonType) { + $OCLog.sessiontype = $UserState.logonType + } + + if ($UserState.userAccountType) { + $OCLog.objectname = $UserState.userAccountType + } + + if ($UserState.domainName) { + $OCLog.domainorigin = $UserState.domainName + } + + if ($UserState.riskScore) { + $OCLog.size = $UserState.riskScore + } + + $OCLog.vendorinfo = 'https://docs.microsoft.com/en-us/graph/api/resources/usersecuritystate?view=graph-rest-1.0' + + Try { + Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($OCLog | ConvertTo-Json -Depth 10 -Compress) | Out-Null + } Catch { + Write-Host $_ + } + # Reset variables before proceeding to next state + $OCLog.amount = $null + $OCLog.login = $null + $OCLog.sip = $null + $OCLog.domainorigin = $null + $OCLog.size = $null + $OCLog.objectname = $null + $OCLog.sessiontype = $null + $OCLog.subject = $null + $OCLog.vendorinfo = $null + } + $OCLog.quantity = $null + $OCLog.objecttype = $null + } + # Record Log Entry Try { - $SecEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append + $LoggedEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append } Catch { Write-Host $_ } - } Catch { - Write-Host $_ } } + } -# End Section - AzureSentinel - -# Begin Section - DefenderATP -$DefenderATP_SecEvents = Get-LrtAzSecurityAlerts -DefenderATP -Status 'newAlert' -$DefenderATP_LoggedEvents = $SecEventLogs | Where-Object -Property "type" -like "DefenderATP" - -# Loop through results and proceed to process identified new events -ForEach ($DefSecurityEvent in $DefenderATP_SecEvents) { - if ($DefenderATP_LoggedEvents.Id -notcontains $DefSecurityEvent.Id) { - # New Event - # Establish Log Entry - $SecEvent = [PSCustomObject]@{ - log_timestamp = (get-date -Format yyyy-MM-ddTHH:mm:ss:ffffffK) - event_timestamp = $DefSecurityEvent.createdDateTime - type = "DefenderATP" - id = $DefSecurityEvent.id - azureTenantId = $DefSecurityEvent.azureTenantId - severity = $DefSecurityEvent.severity - } - # Write out JSON event for FileBeat - Try { - Invoke-RestMethod -Method 'post' -uri $OCendpoint -Headers @{'Content-Type' = 'application/json; charset=utf-8'} -Body $($DefSecurityEvent | ConvertTo-Json -Depth 50 -Compress) - - # Record Log Entry - Try { - $SecEvent | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Append - } Catch { - Write-Host $_ - } - } Catch { - Write-Host $_ - } + +# Refresh the $State variable from the appended CSV content. +$State = Import-Csv -Path $SecEventSyncLogPath +$StateCleanup = [list[object]]::new() +ForEach ($StateEntry in $State) { + Try { + $AlertDate = [DateTime]$StateEntry.event_timestamp + } Catch { + continue + } + if ($AlertDate -ge $CleanupDate) { + $StateCleanup.add($StateEntry) } } -# End Section - DefenderATP + +# Overwrite the CSV State File representing only the entries that are valid within the script's configured $eventLookBack time period. +$StateCleanup | Export-Csv -Path $SecEventSyncLogPath -NoTypeInformation -Force \ No newline at end of file diff --git a/src/Public/Azure/Graph/Security/Get-LrtAzSecurityAlerts.ps1 b/src/Public/Azure/Graph/Security/Get-LrtAzSecurityAlerts.ps1 index 1ebca04..5459778 100644 --- a/src/Public/Azure/Graph/Security/Get-LrtAzSecurityAlerts.ps1 +++ b/src/Public/Azure/Graph/Security/Get-LrtAzSecurityAlerts.ps1 @@ -219,7 +219,12 @@ Function Get-LrtAzSecurityAlerts { } if ($Top) { - $QueryString = $QueryString + "&`$top=$Top" + if ($QueryString) { + $QueryString = $QueryString + "&`$top=$Top" + } else { + $QueryString = "?`$top=$Top" + } + Write-Verbose "[$Me]: QueryString is [$QueryString]" } $RequestUrl = $RequestUri + $QueryString @@ -236,7 +241,7 @@ Function Get-LrtAzSecurityAlerts { throw [Exception] "[$Me] [$($Err.error.code)]: $($Err.error.message)`n" } - + $ResultsCount = $($Response.value.count) # Cast result to List Write-Verbose "Results: $($Response.value.count)" [List[Object]] $ResultSet = $Response.value @@ -251,7 +256,7 @@ Function Get-LrtAzSecurityAlerts { $PageCount = 0 # Begin paging until no more pages. while ($Paging) { - Write-Verbose ">>>> More Results, calling next page <<<<" + # Iterate the page count $PageCount += 1 # Make the next request, using the nextLink property. @@ -264,25 +269,32 @@ Function Get-LrtAzSecurityAlerts { $Err = Get-RestErrorMessage $_ throw [Exception] "[$Me] [$($Err.error.code)]: $($Err.error.message)`n" } + + $ResultsCount += $($Response.value.count) + Write-Verbose "Current Page: $PageCount Request Results: $($Response.value.count) Total Results: $ResultsCount" # Cast result to List and append to ResultSet - Write-Verbose "Results: $($Response.value.count)" [List[Object]] $PageSet = $Response.value $ResultSet.AddRange($PageSet) - - # Check if done - if ($Response.'@odata.nextLink') { - $NextPage = $Response.'@odata.nextLink' - } elseif ($PageCount -ge 20) { - $Paging = $false + # Prevent from requesting over 5,000 results, GraphAPI pagination halt point. + # The check is if the current count + a return sample result of the last result is greater than 5,000, do not request the next page. + if (($ResultsCount + $($Response.value.count) -lt 5000)) { + if ($Response.'@odata.nextLink') { + $NextPage = $Response.'@odata.nextLink' + } elseif ($PageCount -ge 20) { + Write-Verbose "Stopping pagination. Reason: Iterated over 20 pages. Currently limited to only 20 pages, apply -Top to retrieve more results per request." + $Paging = $false + } else { + Write-Verbose "Stopping pagination. Reason: All results returned." + $Paging = $false + } } else { + Write-Verbose "Stopping pagination. Reason: Result greater than 5,000 values. GraphAPI limited to 5,000 values or less." $Paging = $false } } - } - #> - + } #endregion return $ResultSet diff --git a/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsAccepted.ps1 b/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsAccepted.ps1 index 58793c7..feb828c 100644 --- a/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsAccepted.ps1 +++ b/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsAccepted.ps1 @@ -166,7 +166,7 @@ Function Get-LrAgentsAccepted { [Parameter(Mandatory = $false, Position = 4)] [ValidateSet('all','active','retired', ignorecase=$true)] - [string] $RecordStatus = "all", + [string] $RecordStatus = "active", [Parameter(Mandatory = $false, Position = 5)] diff --git a/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsPending.ps1 b/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsPending.ps1 new file mode 100644 index 0000000..3847624 --- /dev/null +++ b/src/Public/LogRhythm/Admin/Agents/Get-LrAgentsPending.ps1 @@ -0,0 +1,331 @@ +using namespace System +using namespace System.IO +using namespace System.Collections.Generic + +Function Get-LrAgentsPending { + <# + .SYNOPSIS + Returns details of all pending Agents that match the specified criteria. + + This cmdlet is only available for LogRhythm SIEM's with version 7.5.0 and greater. + .DESCRIPTION + Get-LrAgentsPending returns a list of pending Agents, including details. + .PARAMETER Credential + PSCredential containing an API Token in the Password field. + .PARAMETER PageCount + Integer representing number of pages to return. Default is maximum, 1000. + .PARAMETER OrderBy + Sorts records by name or Id. + .PARAMETER Direction + Sorts records by ascending or descending. + + Valid values: "asc" "desc" + .PARAMETER Name + String used to search records by Name. + .PARAMETER AgentLicenseType + Filter based by license type. + + Valid values: "None" "SystemMonitorBasic" "SystemMonitor" + .PARAMETER SearchScope + Filters by search scope. + + Valid values: "SystemMonitorSearch" "ParentEntitySearch" "GlobalSearch" + .PARAMETER Entity + Parameter for specifying the existing LogRhythm Entity for the new Host record to be set to. + This parameter can be provided either Entity Name or Entity Id but not both. + + [System.String] (Name) or [System.Int32] + Specifies a LogRhythm Entity object by providing one of the following property values: + + Entity Name (as System.String), e.g. "Segment Bravo" + + Entity Id (as System.String or System.Int32), e.g. 202 + .PARAMETER Version + The deployment version of the component. + + Version schema: (\d[6-9]?).?((\d[0-9]?).?){0,2}(\d[0-9]{0,4}) + .PARAMETER AgentType + Filter results by type of agent. + + Valid values: "None" "Windows" "Linux" "Solaris" "Aix" "Hpux" "All" + .PARAMETER LoadBalanced + Filters results by load balanced status of component. + + Valid values: true, false + .PARAMETER RecordStatus + Filter records by object Record Status. + + Valid values: "all" "active" "retired" + .PARAMETER FetchAIERecords + Filters results by whether AIE records should be fetched. + + Valud values: true, false + .PARAMETER Exact, + Switch used to specify Name is explicit. + .INPUTS + + .OUTPUTS + PSCustomObject representing Accepted Agents and their contents. + .EXAMPLE + PS C:\> Get-LrAgentsPending + ---- + + .NOTES + LogRhythm-API + .LINK + https://github.com/LogRhythm-Tools/LogRhythm.Tools + #> + + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, Position = 0)] + [string] $Name, + + + [Parameter(Mandatory = $false, Position = 1)] + [string] $Entity, + + + [Parameter(Mandatory = $false, Position = 2)] + [ValidateSet('asc','desc', 'ascending', 'descending', ignorecase=$true)] + [string] $Direction = "ascending", + + + [Parameter(Mandatory = $false, Position = 3)] + [ValidateSet('name','id', ignorecase=$true)] + [string] $OrderBy = "name", + + + [Parameter(Mandatory = $false, Position = 4)] + [ValidateSet('all','pending','rejected', ignorecase=$true)] + [string] $RecordStatus = "pending", + + + [Parameter(Mandatory = $false, Position = 7)] + [string] $Version, + + + [Parameter(Mandatory = $false, Position = 8)] + [ValidateSet('none','windows', 'linux', 'solaris', 'aix', 'hpux', 'all', ignorecase=$true)] + [string] $AgentType, + + + [Parameter(Mandatory = $false, Position = 11)] + [switch] $Exact, + + + [Parameter(Mandatory = $false, Position = 12)] + [int] $PageValuesCount = 1000, + + [Parameter(Mandatory = $false, Position = 13)] + [int] $PageCount = 1, + + + [Parameter(Mandatory = $false, Position = 14)] + [ValidateNotNull()] + [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey + ) + + Begin { + # Request Setup + $BaseUrl = $LrtConfig.LogRhythm.BaseUrl + $Token = $Credential.GetNetworkCredential().Password + + # Define HTTP Headers + $Headers = [Dictionary[string,string]]::new() + $Headers.Add("Authorization", "Bearer $Token") + + # Define HTTP Method + $Method = $HttpMethod.Get + + # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 + Enable-TrustAllCertsPolicy + + # Integer reference + [int32] $_int = 0 + } + + Process { + # Establish General Error object Output + $ErrorObject = [PSCustomObject]@{ + Error = $false + Type = $null + Code = $null + Note = $null + Raw = $null + } + + # Verify version + if ($LrtConfig.LogRhythm.Version -notmatch '7.[5-9].\d') { + $ErrorObject.Error = $true + $ErrorObject.Code = "404" + $ErrorObject.Type = "Cmdlet not supported." + $ErrorObject.Note = "This cmdlet is available in LogRhythm version 7.5.0 and greater." + + return $ErrorObject + } + + #region: Process Query Parameters____________________________________________________ + $QueryParams = [Dictionary[string,string]]::new() + + # PageCount + if ($PageValuesCount) { + $_pageValueCount = $PageValuesCount + } else { + $_pageValueCount = 1000 + } + # PageValuesCount - Amount of Values per Page + $QueryParams.Add("count", $_pageValueCount) + + # Query Offset - PageCount + $Offset = ($PageCount -1) * $_pageValueCount + $QueryParams.Add("offset", $Offset) + + # Filter by Object Name + if ($Name) { + $_name = $Name + $QueryParams.Add("name", $_name) + } + + # Filter by Object Entity Name + if ($Entity) { + # Lookup Entity By ID or Name + if ([int]::TryParse($Entity, [ref]$_int)) { + Write-Verbose "[$Me]: Entity parses as integer." + $EntityLookup = Get-LrEntityDetails -Id $Entity + if ($EntityLookup.Error -eq $true) { + $ErrorObject.Error = $EntityLookup.Error + $ErrorObject.Type = $EntityLookup.Type + $ErrorObject.Code = $EntityLookup.Code + $ErrorObject.Note = $EntityLookup.Note + $ErrorObject.Raw = $_ + return $ErrorObject + } else { + $_entity = $EntityLookup + } + } else { + Write-Verbose "[$Me]: Id does not parse as integer. Performing string lookup." + $EntityLookup = Get-LrEntities -Name $Entity -Exact + if ($EntityLookup.Error -eq $true) { + $ErrorObject.Error = $EntityLookup.Error + $ErrorObject.Type = $EntityLookup.Type + $ErrorObject.Code = $EntityLookup.Code + $ErrorObject.Note = $EntityLookup.Note + $ErrorObject.Raw = $_ + return $ErrorObject + } else { + $_entity = $EntityLookup + } + } + $QueryParams.Add("entity", $($_entity.Name)) + } + + # Return results direction, ascending or descending + if ($Direction) { + if($Direction.ToUpper() -eq "ASC") { + $_direction = "ascending" + } else { + $_direction = "descending" + } + $QueryParams.Add("dir", $_direction) + } + + # RecordStatus + if ($AgentType) { + $_agentType = (Get-Culture).TextInfo.ToTitleCase($AgentType) + $QueryParams.Add("agentType", $_agentType) + } + + # RecordStatus + if ($RecordStatus) { + $_recordStatus = $RecordStatus.ToLower() + $QueryParams.Add("recordStatus", $_recordStatus) + } + + # Version + if ($Version) { + [regex]$ValidStatus = "(\d[6-9]?).?((\d[0-9]?).?){0,2}(\d[0-9]{0,4})" + if ($Version -match $ValidStatus) { + $_version = $Version + $QueryParams.Add("version", $_version) + } else { + $ErrorObject.Error = $true + $ErrorObject.Type = "Format Error" + $ErrorObject.Code = -1 + $ErrorObject.Note = "Provide version that meets regex: (\d[6-9]?).?((\d[0-9]?).?){0,2}(\d[0-9]{0,4})" + $ErrorObject.Raw = "Provide version that meets regex: (\d[6-9]?).?((\d[0-9]?).?){0,2}(\d[0-9]{0,4})" + return $ErrorObject + } + } + + # Build QueryString + if ($QueryParams.Count -gt 0) { + $QueryString = $QueryParams | ConvertTo-QueryString + Write-Verbose "[$Me]: QueryString is [$QueryString]" + } + + # Request URL + $RequestUrl = $BaseUrl + "/lr-admin-api/agents-request/" + $QueryString + + # Send Request + try { + $Response = Invoke-RestMethod $RequestUrl -Headers $Headers -Method $Method + } catch [System.Net.WebException] { + $Err = Get-RestErrorMessage $_ + $ErrorObject.Error = $true + $ErrorObject.Type = "System.Net.WebException" + $ErrorObject.Code = $($Err.statusCode) + $ErrorObject.Note = $($Err.message) + $ErrorObject.Raw = $_ + return $ErrorObject + } + + # Check if pagination is required, if so - paginate! + if ($Response.Count -eq $PageValuesCount) { + DO { + # Increment Page Count / Offset + $PageCount = $PageCount + 1 + $Offset = ($PageCount -1) * $PageValuesCount + # Update Query Paramater + $QueryParams.offset = $Offset + # Apply to Query String + $QueryString = $QueryParams | ConvertTo-QueryString + # Update Query URL + $RequestUrl = $BaseUrl + "/lr-admin-api/agents/" + $QueryString + # Retrieve Query Results + try { + $PaginationResults = Invoke-RestMethod $RequestUrl -Headers $Headers -Method $Method + } catch [System.Net.WebException] { + $Err = Get-RestErrorMessage $_ + $ErrorObject.Error = $true + $ErrorObject.Type = "System.Net.WebException" + $ErrorObject.Code = $($Err.statusCode) + $ErrorObject.Note = $($Err.message) + $ErrorObject.Raw = $_ + return $ErrorObject + } + + # Append results to Response + $Response = $Response + $PaginationResults + } While ($($PaginationResults.Count) -eq $PageValuesCount) + $Response = $Response | Sort-Object -Property Id -Unique + } + + # [Exact] Parameter + # Search "Malware" normally returns both "Malware" and "Malware Options" + # This would only return "Malware" + if ($Exact) { + $Pattern = "^$Name$" + $Response | ForEach-Object { + if(($_.name -match $Pattern) -or ($_.name -eq $Name)) { + Write-Verbose "[$Me]: Exact list name match found." + $List = $_ + return $List + } + } + } else { + return $Response + } + } + + End { + } +} \ No newline at end of file diff --git a/src/Public/LogRhythm/Admin/Hosts/Get-LrHosts.ps1 b/src/Public/LogRhythm/Admin/Hosts/Get-LrHosts.ps1 index 796314f..0b6f998 100644 --- a/src/Public/LogRhythm/Admin/Hosts/Get-LrHosts.ps1 +++ b/src/Public/LogRhythm/Admin/Hosts/Get-LrHosts.ps1 @@ -145,7 +145,9 @@ Function Get-LrHosts { $Method = $HttpMethod.Get # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 - Enable-TrustAllCertsPolicy + Enable-TrustAllCertsPolicy + + $_int = 1 } Process { @@ -177,8 +179,19 @@ Function Get-LrHosts { # Filter by Object Entity Name if ($Entity) { - $_entityName = $Entity - $QueryParams.Add("entity", $_entityName) + # Check if ID value is an integer + if ([int]::TryParse($Entity, [ref]$_int)) { + $EntityLookup = Get-LrEntityDetails -Id $Entity + if ($EntityLookup.error) { + return $EntityLookup + } else { + $_entityName = $EntityLookup.name + } + } else { + $_entityName = $Entity + $QueryParams.Add("entity", $_entityName) + } + } if ($HostIdentifier) { @@ -249,6 +262,9 @@ Function Get-LrHosts { $Response = $Response | Sort-Object -Property Id -Unique } + if ($null -ne $EntityLookup -and $null -ne $Response) { + $Response = $Response | Where-Object -FilterScript {$_.entity.id -eq $EntityLookup.id} + } # [Exact] Parameter # Search "Malware" normally returns both "Malware" and "Malware Options" diff --git a/src/Public/LogRhythm/Admin/Hosts/New-LrHost.ps1 b/src/Public/LogRhythm/Admin/Hosts/New-LrHost.ps1 index 1843e1a..ddcf233 100644 --- a/src/Public/LogRhythm/Admin/Hosts/New-LrHost.ps1 +++ b/src/Public/LogRhythm/Admin/Hosts/New-LrHost.ps1 @@ -230,9 +230,6 @@ Function New-LrHost { # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 Enable-TrustAllCertsPolicy - # Define LogRhythm Version - $LrVersion = $LrtConfig.LRDeployment.Version - # Integer Reference [int32] $_int = 1 } @@ -318,7 +315,9 @@ Function New-LrHost { $_location = $OriginHostRecord.Location } } else { - $_location = $OriginHostRecord.Location + $_location = [PSCustomObject][Ordered]@{ + id = -1 + } } # Ensure proper syntax @@ -411,7 +410,7 @@ Function New-LrHost { id = -1 entity = [PSCustomObject]@{ id = $($_entity.Id) - name = $($_entity.Name) + name = $($_entity.fullName) } name = $Name shortDesc = $shortDesc diff --git a/src/Public/LogRhythm/Admin/Hosts/Update-LrHost.ps1 b/src/Public/LogRhythm/Admin/Hosts/Update-LrHost.ps1 index 648f0ad..0abb7c8 100644 --- a/src/Public/LogRhythm/Admin/Hosts/Update-LrHost.ps1 +++ b/src/Public/LogRhythm/Admin/Hosts/Update-LrHost.ps1 @@ -225,7 +225,7 @@ Function Update-LrHost { [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 14)] - [bool] $UseEventlogCredentials = $false, + [bool] $UseEventlogCredentials, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 15)] @@ -525,20 +525,18 @@ Function Update-LrHost { $_osType = $OriginHostRecord.osType } - if ($OriginHostRecord.eventlogUsername) { - $_eventlogUsername = $OriginHostRecord.eventlogUsername - } - - if ($OriginHostRecord.eventlogPassword) { - $_eventlogPassword = $OriginHostRecord.eventlogPassword + if ($UseEventlogCredentials) { + $_useEventlogCredentials = $UseEventlogCredentials + } else { + $_useEventlogCredentials = $OriginHostRecord.useEventlogCredentials } # Establish JSON Body contents $BodyContents = [PSCustomObject]@{ id = $Guid entity = [PSCustomObject]@{ - id = $($_entity.Id) - name = $($_entity.Name) + id = $($_entity.Id) + name = $($_entity.fullName) } name = $_name shortDesc = $_shortDesc @@ -551,7 +549,7 @@ Function Update-LrHost { location = $_location os = $_os osVersion = $_osVersion - useEventlogCredentials = $UseEventlogCredentials + useEventlogCredentials = $_useEventlogCredentials osType = $_osType } diff --git a/src/Public/LogRhythm/Admin/Identities/Update-LrIdentity.ps1 b/src/Public/LogRhythm/Admin/Identities/Update-LrIdentity.ps1 new file mode 100644 index 0000000..60101e8 --- /dev/null +++ b/src/Public/LogRhythm/Admin/Identities/Update-LrIdentity.ps1 @@ -0,0 +1,254 @@ +using namespace System +using namespace System.IO +using namespace System.Collections.Generic + +Function Update-LrIdentity { + <# + .SYNOPSIS + Update an Identity to TrueIdentity. + .DESCRIPTION + Update-LrIdentity returns an object containing the detailed results of the updated Identity. + .PARAMETER IdentityId + Identity ID # for the True Identity record to be updated. This is a required parameter. + .PARAMETER NameFirst + First name string value for the TrueIdentity record. + .PARAMETER NameMiddle + Middle name string value for the TrueIdentity record. + .PARAMETER NameLast + Last name string value for the TrueIdentity record. + .PARAMETER DisplayIdentifier + DisplayIdentifier string value for the TrueIdentity record. + .PARAMETER Department + Department string value for the TrueIdentity record. + .PARAMETER Manager + Manager string value for the TrueIdentity record. + .PARAMETER Company + Company string value for the TrueIdentity record. + .PARAMETER Title + Title string value for the TrueIdentity record. + .PARAMETER AddressCity + AddressCity string value for the TrueIdentity record. + .PARAMETER PassThru + Switch paramater that will enable the return of the output object from the cmdlet. + .PARAMETER Credential + PSCredential containing an API Token in the Password field. + .OUTPUTS + PSCustomObject representing LogRhythm TrueIdentity Identity and its status. + .EXAMPLE + Update-LrIdentity -IdentityId 111 -Department "TAM" -Manager "Eric Hart" -Title "TrueID Service Account" -Company "LogRhythm, Inc." -AddressCity "Boulder" -PassThru + + nameFirst : svc + nameMiddle : + nameLast : LRIdentitySync + displayIdentifier : svc_lridentitysync@tam.lr + company : LogRhythm, Inc. + department : TAM + title : TrueID Service Account + manager : Eric Hart + addressCity : Boulder + recordStatus : Active + .EXAMPLE + Update-LrIdentity -IdentityId 411 -Department "TAM" -Manager "Eric Hart" -Company "LogRhythm, Inc." -AddressCity "Boulder" -PassThru + + Error : True + Note : IdentityID 411 does not exist or you don't have access to see it + Code : 404 + Type : System.Net.WebException + IdentityId : 411 + Raw : {"statusCode":404,"message":"IdentityID 411 does not exist or you don't have access to see it"} + .NOTES + LogRhythm-API + .LINK + https://github.com/LogRhythm-Tools/LogRhythm.Tools + #> + + [CmdletBinding()] + Param( + [Parameter(Mandatory = $true, valuefrompipelinebypropertyname = $true, Position = 0)] + [int32] $IdentityId, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 1)] + [string] $NameFirst, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 2)] + [string] $NameMiddle, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 3)] + [string] $NameLast, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 4)] + [string] $DisplayIdentifier, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 5)] + [string] $Department, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 6)] + [string] $Manager, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 7)] + [string] $Company, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 8)] + [string] $Title, + + + [Parameter(Mandatory = $false, valuefrompipelinebypropertyname = $true, Position = 9)] + [string] $AddressCity, + + + [Parameter(Mandatory = $false, Position = 10)] + [switch] $PassThru, + + + [Parameter(Mandatory = $false, Position = 11)] + [ValidateNotNull()] + [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey + ) + + Begin { + # Request Setup + $BaseUrl = $LrtConfig.LogRhythm.BaseUrl + $Token = $Credential.GetNetworkCredential().Password + + # Define HTTP Headers + $Headers = [Dictionary[string,string]]::new() + $Headers.Add("Authorization", "Bearer $Token") + $Headers.Add("Content-Type","application/json") + + # Define HTTP Method + $Method = $HttpMethod.Put + + # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 + Enable-TrustAllCertsPolicy + + # Establish Object for new TrueIdentity records + $NewIdentities = [list[object]]::new() + } + + Process { + # Establish General Error object Output + $ErrorObject = [PSCustomObject]@{ + Error = $false + Note = $null + Code = $null + Type = $null + NameFirst = $NameFirst + NameLast = $NameLast + Raw = $null + } + $ExistingIdentity = Get-LrIdentityById -IdentityId $IdentityId + if ($ExistingIdentity.error -eq $true) { + return $ExistingIdentity + } + + # Section - Build JSON Body - Begin + $Identity = [PSCustomObject]@{} + + + + # NameFirst - Required + if ($NameFirst) { + $Identity | Add-Member -NotePropertyName nameFirst -NotePropertyValue $NameFirst + } else { + $Identity | Add-Member -NotePropertyName nameFirst -NotePropertyValue $ExistingIdentity.nameFirst + } + + # NameMiddle - Optional + if ($NameMiddle) { + $Identity | Add-Member -NotePropertyName nameMiddle -NotePropertyValue $NameFirst + } else { + $Identity | Add-Member -NotePropertyName nameMiddle -NotePropertyValue $ExistingIdentity.nameMiddle + } + + + # NameLast - Required + if ($NameMiddle) { + $Identity | Add-Member -NotePropertyName nameLast -NotePropertyValue $NameLast + } else { + $Identity | Add-Member -NotePropertyName nameLast -NotePropertyValue $ExistingIdentity.nameLast + } + + # DisplayIdentifier - Required + if ($DisplayIdentifier) { + $Identity | Add-Member -NotePropertyName displayIdentifier -NotePropertyValue $DisplayIdentifier + } else { + $Identity | Add-Member -NotePropertyName displayIdentifier -NotePropertyValue $ExistingIdentity.displayIdentifier + } + + # Company, Department, Title, Manager, AddressCity, DomainNAme - Optional + if ($Company) { + $Identity | Add-Member -NotePropertyName company -NotePropertyValue $Company + } else { + $Identity | Add-Member -NotePropertyName company -NotePropertyValue $ExistingIdentity.company + } + + if ($Department) { + $Identity | Add-Member -NotePropertyName department -NotePropertyValue $Department + } else { + $Identity | Add-Member -NotePropertyName department -NotePropertyValue $ExistingIdentity.department + } + + if ($Title) { + $Identity | Add-Member -NotePropertyName title -NotePropertyValue $Title + } else { + $Identity | Add-Member -NotePropertyName title -NotePropertyValue $ExistingIdentity.title + } + + if ($Manager) { + $Identity | Add-Member -NotePropertyName manager -NotePropertyValue $Manager + } else { + $Identity | Add-Member -NotePropertyName manager -NotePropertyValue $ExistingIdentity.manager + } + + if ($AddressCity) { + $Identity | Add-Member -NotePropertyName addressCity -NotePropertyValue $AddressCity + } else { + $Identity | Add-Member -NotePropertyName addressCity -NotePropertyValue $ExistingIdentity.addressCity + } + + if ($RecordStatus) { + $Identity | Add-Member -NotePropertyName recordStatus -NotePropertyValue $RecordStatus + } else { + $Identity | Add-Member -NotePropertyName recordStatus -NotePropertyValue $ExistingIdentity.recordStatus + } + + # Establish Body Contents + $BodyContents = $($Identity | ConvertTo-Json -Depth 5) + + Write-Verbose $BodyContents + + # Define Query URL + $RequestUrl = $BaseUrl + "/lr-admin-api/identities/$IdentityId/" + + # Send Request + try { + $Response = Invoke-RestMethod $RequestUrl -Headers $Headers -Method $Method -Body $BodyContents + } catch [System.Net.WebException] { + $Err = Get-RestErrorMessage $_ + $ErrorObject.Error = $true + $ErrorObject.Type = "System.Net.WebException" + $ErrorObject.Code = $($Err.statusCode) + $ErrorObject.Note = $($Err.message) + $ErrorObject.Raw = $_ + return $ErrorObject + } + + + if ($PassThru) { + return $Response + } + + } + + End { + + } +} \ No newline at end of file diff --git a/src/Public/LogRhythm/Admin/Lists/Get-LrList.ps1 b/src/Public/LogRhythm/Admin/Lists/Get-LrList.ps1 index 3d3bbcf..9bcca8f 100644 --- a/src/Public/LogRhythm/Admin/Lists/Get-LrList.ps1 +++ b/src/Public/LogRhythm/Admin/Lists/Get-LrList.ps1 @@ -124,6 +124,23 @@ Function Get-LrList { return $ErrorObject } + switch ($Response.listType) { + 'MsgSource' { + ForEach ($Item in $Response.items) { + $ItemName = Get-LrLogSourceDetails -Id $Item.value + $Item | Add-Member -MemberType NoteProperty -Name 'valueName' -Value $ItemName.Name + } + } + 'MsgSourceType' { + $LSTypes = Get-LrLogSourceTypes + ForEach ($Item in $Response.items) { + $ItemName = $LSTypes | Where-Object -filterscript {$_.id -eq $Item.value} + $Item | Add-Member -MemberType NoteProperty -Name 'valueName' -Value $ItemName.Name + } + } + default {} + } + # Process Results if ($ValuesOnly) { diff --git a/src/Public/LogRhythm/Alarms/Add-LrAlarmComment.ps1 b/src/Public/LogRhythm/Alarms/Add-LrAlarmComment.ps1 index 40b4d92..49da288 100644 --- a/src/Public/LogRhythm/Alarms/Add-LrAlarmComment.ps1 +++ b/src/Public/LogRhythm/Alarms/Add-LrAlarmComment.ps1 @@ -43,11 +43,11 @@ Function Add-LrAlarmComment { [CmdletBinding()] Param( - [Parameter(Mandatory = $true, Position = 0)] + [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [Int32] $AlarmId, - [Parameter(Mandatory = $true, Position = 1)] + [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [String] $Comment, diff --git a/src/Public/LogRhythm/Alarms/Get-LrAlarm.ps1 b/src/Public/LogRhythm/Alarms/Get-LrAlarm.ps1 index c95fd4b..8736722 100644 --- a/src/Public/LogRhythm/Alarms/Get-LrAlarm.ps1 +++ b/src/Public/LogRhythm/Alarms/Get-LrAlarm.ps1 @@ -65,11 +65,19 @@ Function Get-LrAlarm { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter( + Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + Position = 0 + )] [Int32] $AlarmId, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter( + Mandatory = $false, + Position = 1 + )] [switch] $ResultsOnly, diff --git a/src/Public/LogRhythm/Alarms/Get-LrAlarmEvents.ps1 b/src/Public/LogRhythm/Alarms/Get-LrAlarmEvents.ps1 index 2c3d856..10838d2 100644 --- a/src/Public/LogRhythm/Alarms/Get-LrAlarmEvents.ps1 +++ b/src/Public/LogRhythm/Alarms/Get-LrAlarmEvents.ps1 @@ -143,11 +143,18 @@ Function Get-LrAlarmEvents { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 0 + )] [Int32] $AlarmId, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter( + Mandatory = $false, + Position = 1 + )] [switch] $ResultsOnly, diff --git a/src/Public/LogRhythm/Alarms/Get-LrAlarms.ps1 b/src/Public/LogRhythm/Alarms/Get-LrAlarms.ps1 index a0d2360..422cabf 100644 --- a/src/Public/LogRhythm/Alarms/Get-LrAlarms.ps1 +++ b/src/Public/LogRhythm/Alarms/Get-LrAlarms.ps1 @@ -117,24 +117,44 @@ Function Get-LrAlarms { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 0 + )] [string] $Name, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 1 + )] [string] $Entity, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 2 + )] [string] $Alarm, - [Parameter(Mandatory = $false, Position = 3)] - [string] $Notification, + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 3 + )] + [bool] $Notification, - [Parameter(Mandatory = $false, Position = 4)] - [string] $CaseId, + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 4 + )] + [bool] $CaseAssociation, [Parameter(Mandatory = $false, Position = 5)] @@ -144,7 +164,7 @@ Function Get-LrAlarms { [Parameter(Mandatory = $false, Position = 6)] [ValidateSet('asc','desc', 'ascending', 'descending', ignorecase=$true)] - [string] $Direction = "asc", + [string] $Direction = "desc", [Parameter(Mandatory = $false, Position = 7)] @@ -167,6 +187,10 @@ Function Get-LrAlarms { [int] $PageCount = 1, + [Parameter(Mandatory = $false, Position = 20)] + [int] $MaxPages = 1000, + + [Parameter(Mandatory = $false, Position = 12)] [ValidateNotNull()] [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey @@ -233,14 +257,12 @@ Function Get-LrAlarms { $QueryParams.Add("entityName", $_entityName) } - if ($CaseId) { - $CaseIdStatus = Test-LrCaseIdFormat -Id $CaseId - if (($CaseIdStatus.IsValid -eq $true) -and ($null -ne $CaseIdStatus.CaseNumber) ) { - $_caseId = $CaseIdStatus.CaseGuid.replace("-","") - } else { - $_caseId = $CaseId - } - $QueryParams.Add("caseAssociation", $_caseId) + if ($CaseAssociation) { + $QueryParams.Add("caseAssociation", $CaseAssociation) + } + + if ($Notification) { + $QueryParams.Add("Notification", $Notification) } if ($DateInserted) { @@ -315,18 +337,20 @@ Function Get-LrAlarms { } - if ($Response.alarmsCount -eq $PageValuesCount) { - write-verbose "Response Count: $($Response.alarmsCount) Page Value Count: $PageValuesCount" + if ($Response.alarmsCount -eq $PageValuesCount -and ($MaxPages -gt 1)) { + $PageNumber = 1 + write-verbose "Response Count: $($Response.alarmsCount) Page Value Count: $PageValuesCount Page: $PageNumber Max Pages: $MaxPages" $AlarmResults = [list[object]]::new() - ForEach ($AlarmDetails in $Response.alarmSearchDetails) { + ForEach ($AlarmDetails in $Response.alarmsSearchDetails) { if ($AlarmResults.alarmId -notcontains $AlarmDetails.alarmId) { $AlarmResults.Add($AlarmDetails) } } DO { + $PageNumber = $PageNumber + 1 # Increment Offset - $Offset = $Offset + 1 + $Offset = $Offset + (1 * $PageValuesCount) # Update Query Paramater $QueryParams.offset = $Offset # Apply to Query String @@ -352,8 +376,9 @@ Function Get-LrAlarms { } } - write-verbose "Response Count: $($PaginationResults.alarmsCount) Page Value Count: $PageValuesCount" - } While ($($PaginationResults.alarmsCount) -eq $PageValuesCount) + write-verbose "Response Count: $($PaginationResults.alarmsCount) Page Value Count: $PageValuesCount Page: $PageNumber Max Pages: $MaxPages" + } While (($($PaginationResults.alarmsCount) -eq $PageValuesCount) -and ($PageNumber -lt $MaxPages)) + #$AlarmResults = $AlarmResults | Sort-Object -Property alarmId -Unique $Response = [PSCustomObject]@{ alarmsSearchDetails = $AlarmResults diff --git a/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 b/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 index 5dbfead..74e5b7d 100644 --- a/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 +++ b/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 @@ -218,6 +218,10 @@ Function Get-LrCases { [ValidateNotNull()] [string[]] $Tags, + [Parameter(Mandatory = $false, Position = 7)] + [ValidateSet("all","any")] + [string] $TagSearchMode, + [Parameter(Mandatory = $false, Position = 7)] [ValidateNotNull()] @@ -404,14 +408,63 @@ Function Get-LrCases { # Tags (Exclude Tags are removed from the final result) if ($Tags) { $_tagNumbers = [list[string]]::new() - ForEach ($Tag in $Tags) { - $_tagNumbers.add($($Tag | Get-LrTagNumber)) + # With TagSearchMode All, all tags must exist in order to be able to return results. + # If a tag requested does not exist, return the request with an error for missing tag. + switch ($TagSearchMode) { + "all" { + ForEach ($Tag in $Tags) { + $TagResults = $Tag | Get-LrTagNumber + if ($TagResults) { + if ($_tagNumbers -notcontains $TagResults) { + $_tagNumbers.add($TagResults) + } + } else { + $ErrorObject.Error = $true + $ErrorObject.Type = "Tag not found." + $ErrorObject.Code = 404 + $ErrorObject.Note = "Tag [$Tag] not found." + return $ErrorObject + } + Start-Sleep 0.1 + } + } + "any" { + ForEach ($Tag in $Tags) { + $TagResults = $Tag | Get-LrTagNumber + if ($TagResults) { + if ($_tagNumbers -notcontains $TagResults) { + $_tagNumbers.add($TagResults) + } + } + Start-Sleep 0.1 + } + if ($null -eq $TagResults -or $TagResults.count -eq 0) { + $ErrorObject.Error = $true + $ErrorObject.Type = "Tag not found." + $ErrorObject.Code = 404 + $ErrorObject.Note = "Tags $([string]::Join(', ', $Tags)) not found." + return $ErrorObject + } + } + default { + ForEach ($Tag in $Tags) { + $TagResults = $Tag | Get-LrTagNumber + if ($TagResults) { + if ($_tagNumbers -notcontains $TagResults) { + $_tagNumbers.add($TagResults) + } + } + Start-Sleep 0.1 + } + } } + if ($_tagNumbers.count -gt 1) { $_tags = $_tagNumbers -join ',' } else { $_tags = $_tagNumbers } + $QueryParams.Add("tagNumber", $_tags) } @@ -547,18 +600,14 @@ Function Get-LrCases { $Exclude = $false # Inspect each case's tags - if ($Tags.count -eq $_tagNumbers.count) { - foreach ($_tag in $_tagNumbers) { - if ($case.tags.number -notcontains $_tag) { - Write-Verbose "Case #: $($Case.number) Mising Tag #: $_tag" - $Exclude = $true - } + foreach ($_tag in $_tagNumbers) { + if ($case.tags.number -notcontains $_tag) { + Write-Verbose "Case #: $($Case.number) Mising Tag #: $_tag" + $Exclude = $true } - } else { - Write-Verbose "Total number of Tag Names submitted: $($Tags.count) does not match Tag Lookup Quantity: $($_tagNumbers.count)" - $Exclude = $true } + if ($Exclude -eq $true) { $FilterResults.add($case) | Out-Null } @@ -570,6 +619,36 @@ Function Get-LrCases { } } + if ($TagSearchMode -like "any" -and $Tags) { + $FilterResults = [List[object]]::new() + # Check every case + foreach ($Case in $Results) { + $Include = $false + + # Inspect each case's tags + foreach ($_tag in $_tagNumbers) { + if ($case.tags.number -contains $_tag) { + Write-Verbose "Case #: $($Case.number) Tag #: $_tag" + $Include = $true + } + } + + if ($Include -eq $true) { + if ($FilterResults -notcontains $case) { + $FilterResults.add($case) | Out-Null + } + } + } + + # Iterate through FilterResults to remove from Results + if ($FilterResults.count -ge 1) { + $Results = $FilterResults + } else { + return $null + } + + } + # For Summary, return a formatted report if ($Summary) { return Format-LrCaseListSummary -InputObject $Results diff --git a/src/Public/LogRhythm/Case/General/Update-LrCaseOwner.ps1 b/src/Public/LogRhythm/Case/General/Update-LrCaseOwner.ps1 index 05f73f8..0f03a7a 100644 --- a/src/Public/LogRhythm/Case/General/Update-LrCaseOwner.ps1 +++ b/src/Public/LogRhythm/Case/General/Update-LrCaseOwner.ps1 @@ -39,12 +39,16 @@ Function Update-LrCaseOwner { [ValidateNotNullOrEmpty()] [string] $Name, - + [Parameter(Mandatory = $false, Position = 2)] - [switch] $PassThru, + [switch] $Force, [Parameter(Mandatory = $false, Position = 3)] + [switch] $PassThru, + + + [Parameter(Mandatory = $false, Position = 4)] [ValidateNotNull()] [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey ) @@ -109,6 +113,29 @@ Function Update-LrCaseOwner { } # Make sure user is a collaborator on case + $CaseResults = Get-LrCaseById -Id $Id + if ($CaseResults -and $CaseResults.Error -ne $true) { + $CaseCollaborators = $CaseResults | Select-Object -ExpandProperty 'collaborators' + if (!($CaseCollaborators.number -contains $UserNumber)) { + if ($Force) { + $AddCollabResults = Add-LrCaseCollaborators -Id $Id -Numbers $UserNumber -PassThru + Start-Sleep $global:APISleep + if ($AddCollabResults.Error -eq $true) { + return $AddCollabResults + } + } else { + $ErrorObject.Code = -1 + $ErrorObject.Type = "Input Validation" + $ErrorObject.Note = "New case owner is not an existing case collaborator. Manually add the target user to the case as a collaborator or re-run this cmdlet with the -Force flag." + $ErrorObject.Error = $true + $ErrorObject.Raw = $null + return $ErrorObject + } + } + } elseif ($CaseResults.Error) { + return $CaseResults + } + $CaseCollaborators = Get-LrCaseById -Id $CaseNumber | Select-Object -ExpandProperty collaborators if ($CaseCollaborators) { if (!$CaseCollaborators.number -contains $UserNumber) { @@ -123,7 +150,7 @@ Function Update-LrCaseOwner { throw [ArgumentException] "Unable to find an active LogRhythm ID for $Name." } #endregion - + #region: Send Request From d06279c6176cb5c5d0154dd5879695bb1065e1db Mon Sep 17 00:00:00 2001 From: John Berkers Date: Wed, 9 Mar 2022 03:16:12 +1100 Subject: [PATCH 2/3] Add RuleBlockId to AIE Drilldown Results/Summary data (#82) * Add RuleBlockId to AIE Summary Fields * Un-change get-lraiesummary * get-lraiesummary consistent with get-lraiedrilldown * Repeated data was eliminated * Full sync with aiedrilldown * PIFType is text in summary * Re-order fields, make ruleblockid Co-authored-by: John Berkers --- src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 | 1 + src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 b/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 index 10e0700..53fa9b8 100644 --- a/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 +++ b/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 @@ -194,6 +194,7 @@ Function Get-LrAieDrilldown { foreach ($ruleBlock in $_dd.RuleBlocks) { foreach ($field in $ruleBlock.DDSummaries) { $fields = [PSCustomObject]@{ + RuleBlockId = ($ruleBlock.RuleBlockId) FieldName = $($field.PIFType | Get-PIFTypeName) FieldValue = ($field.DrillDownSummaryLogs | ConvertFrom-Json).field FieldCount = ($field.DrillDownSummaryLogs | ConvertFrom-Json).value diff --git a/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 b/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 index 6d5da95..67c2a5f 100644 --- a/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 +++ b/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 @@ -154,16 +154,18 @@ Function Get-LrAieSummary { $_dd = $Response.Data.drilldownsummary # Get Summary Fields - $SummaryFields = [List[Dictionary[string,string]]]::new() + $SummaryFields = [List[object]]::new() foreach ($ruleBlock in $_dd.RuleBlocks) { - $fields = [Dictionary[string,string]]::new() - foreach ($field in $ruleBlock.DDSummaries) { - $FieldName = $field.PIFType - $FieldValue = ($field.DrillDownSummaryLogs | ConvertFrom-Json).field - $fields.Add($FieldName, $FieldValue) + $fields = [PSCustomObject]@{ + RuleBlockId = ($ruleBlock.RuleBlockId) + FieldName = $($field.PIFType) + FieldValue = ($field.DrillDownSummaryLogs | ConvertFrom-Json).field + FieldCount = ($field.DrillDownSummaryLogs | ConvertFrom-Json).value + } + $SummaryFields.Add($fields) } - $SummaryFields.Add($fields) + } # Done! From 1eddb4e493c4494600db478d7b252e9afa92a67b Mon Sep 17 00:00:00 2001 From: Eric H Date: Tue, 8 Mar 2022 09:26:48 -0700 Subject: [PATCH 3/3] Dev 1.2.5 (#84) * Add ability to retrieve a limited quantity of pages of results. * Add ValueFromPipelineByProperty for cmdlets * Add update handler for Value/Array handler null entries * Add ValueFromPipelineByPropertyName and Handler for null array items in value field * Create Send-LrSdpWebhook.ps1 Submits a log message in to a LogRhythm Open Collector Webhook Beat for log ingestion. Send-LrSdpWebhook -Account 'ehart' -sip '192.168.5.6' -dip '192.168.5.7' -OCUrl 'http://172.17.5.20:8085/webhook' -fqbn 'webhook_SDPGenericExample' --- .../LogRhythm/AIE/Get-LrAieDrilldown.ps1 | 6 +- src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 | 16 +- src/Public/LogRhythm/AIE/Get-PIFTypeName.ps1 | 1 + .../LogRhythm/Admin/Lists/Add-LrListItem.ps1 | 15 +- .../Admin/Lists/Sync-LrListItems.ps1 | 6 + .../Admin/Location/Get-LrLocations.ps1 | 8 +- .../LogSources/Get-LrLogSourceDetails.ps1 | 2 +- .../Admin/LogSources/Get-LrLogSourceTypes.ps1 | 2 +- .../Admin/LogSources/Get-LrLogSources.ps1 | 22 +- .../Admin/Networks/Find-LrNetworkByIP.ps1 | 8 +- .../Admin/Networks/Get-LrNetworkDetails.ps1 | 2 +- .../Admin/Networks/Get-LrNetworks.ps1 | 14 +- .../Admin/Networks/Update-LrNetwork.ps1 | 6 +- .../Get-LrNotificationGroupUsers.ps1 | 6 +- .../Get-LrNotificationGroups.ps1 | 8 +- .../LogRhythm/Alarms/Get-LrAlarmHistory.ps1 | 56 ++- .../LogRhythm/Case/General/Get-LrCases.ps1 | 6 +- src/Public/LogRhythm/OC/Send-LrSdpWebhook.ps1 | 424 ++++++++++++++++++ 18 files changed, 542 insertions(+), 66 deletions(-) create mode 100644 src/Public/LogRhythm/OC/Send-LrSdpWebhook.ps1 diff --git a/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 b/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 index 53fa9b8..69a3dc8 100644 --- a/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 +++ b/src/Public/LogRhythm/AIE/Get-LrAieDrilldown.ps1 @@ -65,15 +65,15 @@ Function Get-LrAieDrilldown { #region: Parameters [CmdletBinding()] Param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [int] $AlarmId, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [int] $RetryAttempts = 18, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [int] $RetryWaitSeconds = 10, diff --git a/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 b/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 index 67c2a5f..0576407 100644 --- a/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 +++ b/src/Public/LogRhythm/AIE/Get-LrAieSummary.ps1 @@ -70,21 +70,21 @@ Function Get-LrAieSummary { #region: Parameters [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] - [ValidateNotNull()] - [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey, - - - [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1)] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [int] $AlarmId, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [int] $RetryAttempts = 18, + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] + [int] $RetryWaitSeconds = 10, + + [Parameter(Mandatory = $false, Position = 3)] - [int] $RetryWaitSeconds = 10 + [ValidateNotNull()] + [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey ) #endregion diff --git a/src/Public/LogRhythm/AIE/Get-PIFTypeName.ps1 b/src/Public/LogRhythm/AIE/Get-PIFTypeName.ps1 index 1435eaa..dd749f6 100644 --- a/src/Public/LogRhythm/AIE/Get-PIFTypeName.ps1 +++ b/src/Public/LogRhythm/AIE/Get-PIFTypeName.ps1 @@ -25,6 +25,7 @@ Function Get-PIFTypeName { [Parameter( Mandatory = $true, ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, Position = 0 )] [int] $PIFType diff --git a/src/Public/LogRhythm/Admin/Lists/Add-LrListItem.ps1 b/src/Public/LogRhythm/Admin/Lists/Add-LrListItem.ps1 index e810434..c93456a 100644 --- a/src/Public/LogRhythm/Admin/Lists/Add-LrListItem.ps1 +++ b/src/Public/LogRhythm/Admin/Lists/Add-LrListItem.ps1 @@ -81,20 +81,20 @@ Function Add-LrListItem { [CmdletBinding()] Param( - [Parameter(Mandatory = $true, Position = 0)] + [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [ValidateNotNull()] [object] $Name, - [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [string[]] $Value, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [string] $ItemType, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [switch] $LoadListItems, @@ -128,6 +128,10 @@ Function Add-LrListItem { # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 Enable-TrustAllCertsPolicy + + if ($Value -is [array]) { + $Value = $Value.Split('',[System.StringSplitOptions]::RemoveEmptyEntries) + } } Process { @@ -387,8 +391,9 @@ Function Add-LrListItem { if ($Value -is [array]) { ForEach ($Entry in $Value) { $IPValid = $Entry -as [IPAddress] -as [Bool] - Write-Verbose "[$Me] IPValid: $IPValid" + if ($IPValid -eq $false) { + Write-Verbose "[$Me] IPValid: $IPValid Value: $Entry" $ErrorObject.Error = $true $ErrorObject.FieldType = "IP" $ErrorObject.TypeMismatch = $true diff --git a/src/Public/LogRhythm/Admin/Lists/Sync-LrListItems.ps1 b/src/Public/LogRhythm/Admin/Lists/Sync-LrListItems.ps1 index 9e6992b..acb9149 100644 --- a/src/Public/LogRhythm/Admin/Lists/Sync-LrListItems.ps1 +++ b/src/Public/LogRhythm/Admin/Lists/Sync-LrListItems.ps1 @@ -122,6 +122,10 @@ Function Sync-LrListItems { Begin { # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 Enable-TrustAllCertsPolicy + + if ($Value -is [array]) { + $Value = $Value.Split('',[System.StringSplitOptions]::RemoveEmptyEntries) + } } Process { @@ -156,6 +160,7 @@ Function Sync-LrListItems { # Process Name if (($Name.GetType() -eq [System.Guid]) -Or (Test-Guid $Name)) { + Write-Verbose "Inspecting for List Name by GUID" $TargetList = Get-LrList -name $Name.ToString() if ($TargetList.Error -eq $true) { $ErrorObject.Error = $true @@ -170,6 +175,7 @@ Function Sync-LrListItems { $OutObject.ListType = $TargetList.ListType } } else { + Write-Verbose "Inspecting for List Name by Exact Name" $TargetList = Get-LrLists -Name $Name.ToString() -Exact if ($TargetList -is [array]) { $ErrorObject.Error = $true diff --git a/src/Public/LogRhythm/Admin/Location/Get-LrLocations.ps1 b/src/Public/LogRhythm/Admin/Location/Get-LrLocations.ps1 index f9ef419..6d6f533 100644 --- a/src/Public/LogRhythm/Admin/Location/Get-LrLocations.ps1 +++ b/src/Public/LogRhythm/Admin/Location/Get-LrLocations.ps1 @@ -62,19 +62,19 @@ Function Get-LrLocations { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Name, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [int32] $Id, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [int32] $ParentLocationId, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [ValidateSet('region','country', ignorecase=$true)] [string] $LocationType, diff --git a/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceDetails.ps1 b/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceDetails.ps1 index 8517a05..038cc8e 100644 --- a/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceDetails.ps1 +++ b/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceDetails.ps1 @@ -115,7 +115,7 @@ Function Get-LrLogSourceDetails { [CmdletBinding()] Param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [ValidateNotNull()] [object] $Id, diff --git a/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceTypes.ps1 b/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceTypes.ps1 index 2347cf1..fe588ac 100644 --- a/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceTypes.ps1 +++ b/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSourceTypes.ps1 @@ -2,7 +2,7 @@ function Get-LrLogSourceTypes { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Name, diff --git a/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSources.ps1 b/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSources.ps1 index 58c2df9..0a940a2 100644 --- a/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSources.ps1 +++ b/src/Public/LogRhythm/Admin/LogSources/Get-LrLogSources.ps1 @@ -175,51 +175,51 @@ Function Get-LrLogSources { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Name, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [int32] $SystemMonitorId, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [int32[]] $HostId, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [ValidateSet('all','active','retired', ignorecase=$true)] [string] $RecordStatus = "active", - [Parameter(Mandatory = $false, Position = 4)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 4)] [int32[]] $EntityId, - [Parameter(Mandatory = $false, Position = 5)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 5)] [ValidateSet('name','id', ignorecase=$true)] [string] $OrderBy = "name", - [Parameter(Mandatory = $false, Position = 6)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 6)] [ValidateSet('asc','desc', ignorecase=$true)] [string] $Direction, - [Parameter(Mandatory = $false, Position = 7)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 7)] [string] $Description, - [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 8)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 8)] [string] $MessageSourceTypeId, - [Parameter(Mandatory = $false, Position = 9)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 9)] [ValidateSet('true','false', ignorecase=$true)] [string] $Virtual, - [Parameter(Mandatory = $false, Position = 10)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 10)] [ValidateSet('true','false', ignorecase=$true)] [string] $LoadBalanced, diff --git a/src/Public/LogRhythm/Admin/Networks/Find-LrNetworkByIP.ps1 b/src/Public/LogRhythm/Admin/Networks/Find-LrNetworkByIP.ps1 index 8294c85..2e9d880 100644 --- a/src/Public/LogRhythm/Admin/Networks/Find-LrNetworkByIP.ps1 +++ b/src/Public/LogRhythm/Admin/Networks/Find-LrNetworkByIP.ps1 @@ -40,19 +40,19 @@ Function Find-LrNetworkByIP { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [Ipaddress]$Ip, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [Ipaddress]$Bip, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [Ipaddress]$Eip, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [String]$Entity, diff --git a/src/Public/LogRhythm/Admin/Networks/Get-LrNetworkDetails.ps1 b/src/Public/LogRhythm/Admin/Networks/Get-LrNetworkDetails.ps1 index f5f0d98..e4119a5 100644 --- a/src/Public/LogRhythm/Admin/Networks/Get-LrNetworkDetails.ps1 +++ b/src/Public/LogRhythm/Admin/Networks/Get-LrNetworkDetails.ps1 @@ -33,7 +33,7 @@ Function Get-LrNetworkDetails { [CmdletBinding()] Param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [ValidateNotNull()] [object] $Id, diff --git a/src/Public/LogRhythm/Admin/Networks/Get-LrNetworks.ps1 b/src/Public/LogRhythm/Admin/Networks/Get-LrNetworks.ps1 index 9bc2104..85e4401 100644 --- a/src/Public/LogRhythm/Admin/Networks/Get-LrNetworks.ps1 +++ b/src/Public/LogRhythm/Admin/Networks/Get-LrNetworks.ps1 @@ -111,33 +111,33 @@ Function Get-LrNetworks { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Name, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [string] $Entity, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [ValidateSet('asc','desc', ignorecase=$true)] [string] $Direction, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [ValidateSet('all','active','retired', ignorecase=$true)] [string] $RecordStatus = "active", - [Parameter(Mandatory = $false, Position = 4)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 4)] [string] $BIP, - [Parameter(Mandatory = $false, Position = 5)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 5)] [string] $EIP, - [Parameter(Mandatory = $false, Position = 6)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 6)] [ValidateSet('name','bip','eip','entity', ignorecase=$true)] [string] $OrderBy = "Entity", diff --git a/src/Public/LogRhythm/Admin/Networks/Update-LrNetwork.ps1 b/src/Public/LogRhythm/Admin/Networks/Update-LrNetwork.ps1 index 40ebebb..8ddcbab 100644 --- a/src/Public/LogRhythm/Admin/Networks/Update-LrNetwork.ps1 +++ b/src/Public/LogRhythm/Admin/Networks/Update-LrNetwork.ps1 @@ -160,7 +160,7 @@ Function Update-LrNetwork { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Id, @@ -508,8 +508,8 @@ Function Update-LrNetwork { #> $BodyContents = [PSCustomObject]@{ entity = [PSCustomObject]@{ - id = $($_entity.Id) - name = $($_entity.Name) + id = $($_entity.Id) + name = $($_entity.Name) } name = $_name shortDesc = $_shortDesc diff --git a/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroupUsers.ps1 b/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroupUsers.ps1 index 6684a3f..ac0e2d0 100644 --- a/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroupUsers.ps1 +++ b/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroupUsers.ps1 @@ -72,15 +72,15 @@ Function Get-LrNotificationGroupUsers { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Name, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [int[]] $id, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [ValidateSet('all','active', 'retired', ignorecase=$true)] [string] $RecordStatus = 'active', diff --git a/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroups.ps1 b/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroups.ps1 index f8ad5b1..226a1f8 100644 --- a/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroups.ps1 +++ b/src/Public/LogRhythm/Admin/NotificationGroups/Get-LrNotificationGroups.ps1 @@ -106,20 +106,20 @@ Function Get-LrNotificationGroups { [CmdletBinding()] Param( - [Parameter(Mandatory = $false, Position = 0)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] [string] $Name, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] [int[]] $Id, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] [ValidateSet('asc', 'desc', 'ascending', 'descending', ignorecase=$true)] [string] $Direction, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] [ValidateSet('name','id', ignorecase=$true)] [string] $OrderBy = "id", diff --git a/src/Public/LogRhythm/Alarms/Get-LrAlarmHistory.ps1 b/src/Public/LogRhythm/Alarms/Get-LrAlarmHistory.ps1 index 0ed7035..5fa3ff3 100644 --- a/src/Public/LogRhythm/Alarms/Get-LrAlarmHistory.ps1 +++ b/src/Public/LogRhythm/Alarms/Get-LrAlarmHistory.ps1 @@ -64,44 +64,80 @@ Function Get-LrAlarmHistory { [CmdletBinding()] Param( - [Parameter(Mandatory = $true, Position = 0)] + [Parameter( + Mandatory = $true, + ValueFromPipelineByPropertyName = $true, + Position = 0 + )] [Int32] $AlarmId, - [Parameter(Mandatory = $false, Position = 1)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 1 + )] [string] $Person, - [Parameter(Mandatory = $false, Position = 2)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 2 + )] [string] $OrderBy, - [Parameter(Mandatory = $false, Position = 3)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 3 + )] [string] $Direction, - [Parameter(Mandatory = $false, Position = 4)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 4 + )] [datetime] $DateUpdated, - [Parameter(Mandatory = $false, Position = 5)] + [Parameter( + Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + Position = 5 + )] [ValidateSet('comment', 'status','rbp', ignorecase=$true)] [string] $Type, - [Parameter(Mandatory = $false, Position = 6)] + [Parameter( + Mandatory = $false, + Position = 6 + )] [switch] $ResultsOnly, - [Parameter(Mandatory = $false, Position = 7)] + [Parameter( + Mandatory = $false, + Position = 7 + )] [int] $PageValuesCount = 1000, - [Parameter(Mandatory = $false, Position = 8)] + [Parameter( + Mandatory = $false, + Position = 8 + )] [int] $PageCount = 1, - [Parameter(Mandatory = $false, Position = 9)] + [Parameter( + Mandatory = $false, + Position = 9 + )] [ValidateNotNull()] [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey ) diff --git a/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 b/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 index 74e5b7d..1e3ea9a 100644 --- a/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 +++ b/src/Public/LogRhythm/Case/General/Get-LrCases.ps1 @@ -292,6 +292,10 @@ Function Get-LrCases { [Parameter(Mandatory = $false, Position = 20)] + [int] $MaxPages = 1000, + + + [Parameter(Mandatory = $false, Position = 21)] [ValidateNotNull()] [pscredential] $Credential = $LrtConfig.LogRhythm.ApiKey ) @@ -551,7 +555,7 @@ Function Get-LrCases { # Append results to Response $Response = $Response + $PaginationResults - } While ($($PaginationResults.Count) -eq $Count) + } While (($($PaginationResults.Count) -eq $Count) -and ($PageNumber -lt $MaxPages)) } } diff --git a/src/Public/LogRhythm/OC/Send-LrSdpWebhook.ps1 b/src/Public/LogRhythm/OC/Send-LrSdpWebhook.ps1 new file mode 100644 index 0000000..f23d8c1 --- /dev/null +++ b/src/Public/LogRhythm/OC/Send-LrSdpWebhook.ps1 @@ -0,0 +1,424 @@ +using namespace System +using namespace System.IO +using namespace System.Collections.Generic +Function Send-LrSdpWebhook { + <# + .SYNOPSIS + Submits a log message in to a LogRhythm Open Collector Webhook Beat for log ingestion. + .EXAMPLE + PS C:\> Send-LrSdpWebhook -Account 'ehart' -sip '192.168.5.6' -dip '192.168.5.7' -OCUrl 'http://172.17.5.20:8085/webhook' -fqbn 'webhook_SDPGenericExample' + .NOTES + LogRhythm-API + .LINK + https://github.com/LogRhythm-Tools/LogRhythm.Tools + account + #> + + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)] + [String] $account, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)] + [String] $action, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 2)] + [Int32] $amount, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 3)] + [String] $command, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 4)] + [String] $cve, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 5)] + [String] $dinterface, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 6)] + [String] $dip, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 7)] + [String] $dmac, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 8)] + [String] $dname, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 9)] + [String] $dnatip, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 10)] + [String] $dnatport, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 11)] + [String] $domainimpacted, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 12)] + [String] $domainorigin, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 13)] + [int32] $dport, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 14)] + [String] $group, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 15)] + [String] $hash, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 16)] + [int32] $kilobytes, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 17)] + [int32] $kilobytesin, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 18)] + [int32] $kilobytesout, + + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 19)] + [String] $login, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 20)] + [int32] $milliseconds, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 21)] + [int32] $minutes, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 22)] + [String] $object, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 23)] + [String] $objectname, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 24)] + [String] $objecttype, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 25)] + [int32] $packetsin, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 26)] + [int32] $packetsout, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 27)] + [int32] $parentprocessid, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 28)] + [String] $parentprocessname, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 29)] + [String] $parentprocesspath, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 30)] + [String] $policy, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 31)] + [String] $process, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 32)] + [int32] $processid, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 33)] + [string] $protname, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 34)] + [int32] $protnum, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 35)] + [int32] $quantity, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 36)] + [int32] $rate, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 37)] + [String] $reason, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 38)] + [String] $recipient, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 39)] + [String] $responsecode, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 40)] + [String] $result, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 41)] + [int32] $seconds, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 42)] + [String] $sender, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 43)] + [String] $serialnumber, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 44)] + [String] $session, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 45)] + [String] $sessiontype, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 46)] + [String] $severity, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 47)] + [String] $sinterface, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 48)] + [String] $sip, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 49)] + [int32] $size, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 50)] + [String] $smac, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 51)] + [String] $sname, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 52)] + [String] $snatip, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 53)] + [String] $snatport, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 54)] + [int32] $sport, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 55)] + [String] $status, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 56)] + [String] $subject, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 57)] + [String] $tag1, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 58)] + [String] $tag2, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 59)] + [String] $tag3, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 60)] + [String] $tag4, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 61)] + [String] $tag5, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 62)] + [String] $tag6, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 63)] + [String] $tag7, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 64)] + [String] $tag8, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 65)] + [String] $tag9, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 66)] + [String] $tag10, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 67)] + [String] $threatid, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 68)] + [String] $threatname, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 69)] + [String] $time, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 70)] + [String] $url, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 71)] + [String] $useragent, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 72)] + [String] $vendorinfo, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 73)] + [String] $version, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 74)] + [String] $vmid, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 75)] + [String] $fqbn, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 76)] + [String] $original_message, + + [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 77)] + [String] $OCUrl, + + [Parameter(Mandatory = $false, Position = 78)] + [int32]$MaxRetries = 4, + + [Parameter(Mandatory = $false, Position = 79)] + [int32]$RetryDelayMs = 250 + ) + + Begin { + # Request Setup + if ($OCUrl) { + $BaseUrl = $OCUrl + } else { + $BaseUrl = $LrtConfig.OC.BaseUrl + } + + + # Define HTTP Headers + $Headers = [Dictionary[string,string]]::new() + $Headers.Add("Content-Type","application/json") + + # Define HTTP Method + $Method = $HttpMethod.post + + # Check preference requirements for self-signed certificates and set enforcement for Tls1.2 + Enable-TrustAllCertsPolicy + + # Variables supporting HTTP Retry for 429 Error handling + $RetryCounter = 0 + } + + Process { + $ErrorObject = [PSCustomObject]@{ + Code = $null + Error = $false + Type = $null + Note = $null + Raw = $null + } + + # Establish Webhook Beat Source Define Parser key to enable JSON/JQ parsing to LogRhythm Metadata fields + $OCLog = [PSCustomObject]@{ + whsdp = $true + } + + if ($Account) { $OCLog | Add-Member -MemberType NoteProperty -Name 'account' -Value $Account -Force } + if ($Action) { $OCLog | Add-Member -MemberType NoteProperty -Name 'action' -Value $Action -Force } + if ($Amount) { $OCLog | Add-Member -MemberType NoteProperty -Name 'amount' -Value $Amount -Force } + if ($Command) { $OCLog | Add-Member -MemberType NoteProperty -Name 'command' -Value $Command -Force } + if ($Cve) { $OCLog | Add-Member -MemberType NoteProperty -Name 'cve' -Value $Cve -Force } + if ($dinterface) { $OCLog | Add-Member -MemberType NoteProperty -Name 'dinterface' -Value $dinterface -Force } + if ($dip) { $OCLog | Add-Member -MemberType NoteProperty -Name 'dip' -Value $dip -Force } + if ($dmac) { $OCLog | Add-Member -MemberType NoteProperty -Name 'dmac' -Value $dmac -Force } + if ($dname) { $OCLog | Add-Member -MemberType NoteProperty -Name 'dname' -Value $dname -Force } + if ($dnatip) { $OCLog | Add-Member -MemberType NoteProperty -Name 'dnatip' -Value $dnatip -Force } + if ($dnatport) { $OCLog | Add-Member -MemberType NoteProperty -Name 'dnatport' -Value $dnatport -Force } + if ($domainimpacted) { $OCLog | Add-Member -MemberType NoteProperty -Name 'domainimpacted' -Value $domainimpacted -Force } + if ($domainorigin) { $OCLog | Add-Member -MemberType NoteProperty -Name 'domainorigin' -Value $domainorigin -Force } + if ($group) { $OCLog | Add-Member -MemberType NoteProperty -Name 'group' -Value $group -Force } + if ($hash) { $OCLog | Add-Member -MemberType NoteProperty -Name 'hash' -Value $hash -Force } + if ($kilobytes) { $OCLog | Add-Member -MemberType NoteProperty -Name 'kilobytes' -Value $kilobytes -Force } + if ($kilobytesin) { $OCLog | Add-Member -MemberType NoteProperty -Name 'kilobytesin' -Value $kilobytesin -Force } + if ($kilobytesout) { $OCLog | Add-Member -MemberType NoteProperty -Name 'kilobytesout' -Value $kilobytesout -Force } + if ($login) { $OCLog | Add-Member -MemberType NoteProperty -Name 'login' -Value $login -Force } + if ($milliseconds) { $OCLog | Add-Member -MemberType NoteProperty -Name 'milliseconds' -Value $milliseconds -Force } + if ($minutes) { $OCLog | Add-Member -MemberType NoteProperty -Name 'minutes' -Value $minutes -Force } + if ($object) { $OCLog | Add-Member -MemberType NoteProperty -Name 'object' -Value $object -Force } + if ($objectname) { $OCLog | Add-Member -MemberType NoteProperty -Name 'objectname' -Value $objectname -Force } + if ($objecttype) { $OCLog | Add-Member -MemberType NoteProperty -Name 'objecttype' -Value $objecttype -Force } + if ($packetsin) { $OCLog | Add-Member -MemberType NoteProperty -Name 'packetsin' -Value $packetsin -Force } + if ($packetsout) { $OCLog | Add-Member -MemberType NoteProperty -Name 'packetsout' -Value $packetsout -Force } + if ($parentprocessid) { $OCLog | Add-Member -MemberType NoteProperty -Name 'parentprocessid' -Value $parentprocessid -Force } + if ($parentprocessname) { $OCLog | Add-Member -MemberType NoteProperty -Name 'parentprocessname' -Value $parentprocessname -Force } + if ($parentprocesspath) { $OCLog | Add-Member -MemberType NoteProperty -Name 'parentprocesspath' -Value $parentprocesspath -Force } + if ($policy) { $OCLog | Add-Member -MemberType NoteProperty -Name 'policy' -Value $policy -Force } + if ($process) { $OCLog | Add-Member -MemberType NoteProperty -Name 'process' -Value $process -Force } + if ($processid) { $OCLog | Add-Member -MemberType NoteProperty -Name 'processid' -Value $processid -Force } + if ($protname) { $OCLog | Add-Member -MemberType NoteProperty -Name 'protname' -Value $protname -Force } + if ($protnum) { $OCLog | Add-Member -MemberType NoteProperty -Name 'protnum' -Value $protnum -Force } + if ($quantity) { $OCLog | Add-Member -MemberType NoteProperty -Name 'quantity' -Value $quantity -Force } + if ($rate) { $OCLog | Add-Member -MemberType NoteProperty -Name 'rate' -Value $rate -Force } + if ($reason) { $OCLog | Add-Member -MemberType NoteProperty -Name 'reason' -Value $reason -Force } + if ($recipient) { $OCLog | Add-Member -MemberType NoteProperty -Name 'recipient' -Value $recipient -Force } + if ($responsecode) { $OCLog | Add-Member -MemberType NoteProperty -Name 'responsecode' -Value $responsecode -Force } + if ($result) { $OCLog | Add-Member -MemberType NoteProperty -Name 'result' -Value $result -Force } + if ($seconds) { $OCLog | Add-Member -MemberType NoteProperty -Name 'seconds' -Value $seconds -Force } + if ($sender) { $OCLog | Add-Member -MemberType NoteProperty -Name 'sender' -Value $sender -Force } + if ($serialnumber) { $OCLog | Add-Member -MemberType NoteProperty -Name 'serialnumber' -Value $serialnumber -Force } + if ($session) { $OCLog | Add-Member -MemberType NoteProperty -Name 'session' -Value $session -Force } + if ($sessiontype) { $OCLog | Add-Member -MemberType NoteProperty -Name 'sessiontype' -Value $sessiontype -Force } + if ($severity) { $OCLog | Add-Member -MemberType NoteProperty -Name 'severity' -Value $severity -Force } + if ($sinterface) { $OCLog | Add-Member -MemberType NoteProperty -Name 'sinterface' -Value $sinterface -Force } + if ($sip) { $OCLog | Add-Member -MemberType NoteProperty -Name 'sip' -Value $sip -Force } + if ($size) { $OCLog | Add-Member -MemberType NoteProperty -Name 'size' -Value $size -Force } + if ($smac) { $OCLog | Add-Member -MemberType NoteProperty -Name 'smac' -Value $smac -Force } + if ($sname) { $OCLog | Add-Member -MemberType NoteProperty -Name 'sname' -Value $sname -Force } + if ($snatip) { $OCLog | Add-Member -MemberType NoteProperty -Name 'snatip' -Value $snatip -Force } + if ($snatport) { $OCLog | Add-Member -MemberType NoteProperty -Name 'snatport' -Value $snatport -Force } + if ($sport) { $OCLog | Add-Member -MemberType NoteProperty -Name 'sport' -Value $sport -Force } + if ($status) { $OCLog | Add-Member -MemberType NoteProperty -Name 'status' -Value $status -Force } + if ($subject) { $OCLog | Add-Member -MemberType NoteProperty -Name 'subject' -Value $subject -Force } + if ($tag1) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag1' -Value $tag1 -Force } + if ($tag2) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag2' -Value $tag2 -Force } + if ($tag3) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag3' -Value $tag3 -Force } + if ($tag4) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag4' -Value $tag4 -Force } + if ($tag5) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag5' -Value $tag5 -Force } + if ($tag6) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag6' -Value $tag6 -Force } + if ($tag7) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag7' -Value $tag7 -Force } + if ($tag8) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag8' -Value $tag8 -Force } + if ($tag9) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag9' -Value $tag9 -Force } + if ($tag10) { $OCLog | Add-Member -MemberType NoteProperty -Name 'tag10' -Value $tag10 -Force } + if ($threatid) { $OCLog | Add-Member -MemberType NoteProperty -Name 'threatid' -Value $threatid -Force } + if ($threatname) { $OCLog | Add-Member -MemberType NoteProperty -Name 'threatname' -Value $threatname -Force } + if ($timestamp8601) { $OCLog | Add-Member -MemberType NoteProperty -Name 'timestamp.iso8601' -Value $timestamp8601 -Force } + if ($timestampepoch) { $OCLog | Add-Member -MemberType NoteProperty -Name 'timestamp.epoch' -Value $timestampepoch -Force } + if ($url) { $OCLog | Add-Member -MemberType NoteProperty -Name 'url' -Value $url -Force } + if ($useragent) { $OCLog | Add-Member -MemberType NoteProperty -Name 'useragent' -Value $useragent -Force } + if ($vendorinfo) { $OCLog | Add-Member -MemberType NoteProperty -Name 'vendorinfo' -Value $vendorinfo -Force } + if ($version) { $OCLog | Add-Member -MemberType NoteProperty -Name 'version' -Value $version -Force } + if ($vmid) { $OCLog | Add-Member -MemberType NoteProperty -Name 'vmid' -Value $vmid -Force } + if ($fqbn) { $OCLog | Add-Member -MemberType NoteProperty -Name 'fullyqualifiedbeatname' -Value $fqbn -Force } + if ($original_message) { $OCLog | Add-Member -MemberType NoteProperty -Name 'original_message' -Value $original_message -Force } + + # Establish Body Contents + $Body = $OCLog | ConvertTo-Json -compress + + # Send Request + Do { + $RetryRequest = $false + Try { + $Response = Invoke-RestMethod $BaseUrl -Headers $Headers -Method $Method -Body $Body + } Catch { + if($_.Exception.Response.StatusCode.value__ -eq 429 ){ + if($RetryCounter -ge $MaxRetries){ + $RetryRequest = $false + } else { + $RetryCounter += 1 + $RetryRequest = $true + Start-Sleep -Milliseconds $RetryDelayMs + } + } else { + return $_ + } + + } + } While ($RetryRequest) + + if ($PassThru) { + return $Response + } + } + + End { + } +} \ No newline at end of file