This is an example of using the composable functions from Nebula API examples using PowerShell. To use the API, a client credential pair and Account ID are required.
Generate client credentials
To generate the credentials, log into Nebula and go to Integrate.
For more information on APIs, see Nebula API Documentation or hover over the tooltip next to OAuth2 Clients on the Integrate page and click the link.
EndpointEvents.ps1
Use this script to retrieve the last 7 days' worth of events from a specific endpoint.
Note: At the bottom of the file, enter your: accountid, client_id, client_secret, and the hostname of the endpoint you'd like to see events for.
#Requires -Version 3.0 # Set the security protocol to TLS 1.2 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 function Get-NebulaToken { <# .SYNOPSIS Authenticate to a Nebula account, returning an OAuth2 token. .DESCRIPTION Authenticates via the Nebula Public API using an OAuth2 Client Pair. Client credentials should be stored/retrieved from secure store as they provide access to your Nebula account. Returns an authentication object containing OAuth2 Bearer Token and metadata with expiry and BaseUrl. .PARAMETER AccountId The Nebula AccountID e.g. aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa This can be found between the first // in the console's URL. E.g. https://cloud.malwarebytes.com/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa/dashboard/securityAdvisor Required to supply this value to others API endpoints that consume Nebula.Token objects. .PARAMETER ClientID ClientID e.g. aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa .PARAMETER ClientSecret ClientSecret e.g. 000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB .PARAMETER Scope OPTIONAL - Specify the read, write, and/or execute scope of the token. Defaults to read write execute. .PARAMETER Verbose OPTIONAL - Indicates that additional details should be displayed. This parameter uses the built-in -Verbose feature to show internal processing steps. Example: Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret -Verbose .OUTPUTS Outputs a Nebula.Token PSCustomObject that can be used as a parameter or in a pipeline for other Nebula API endpoints. .NOTES Header returned contains: 'Authorization' = $TokenRequest.access_token 'AccountID' = $AccountID The ClientID & ClientSecrect should be stoted/retreived from a secure credential store as it provides access to your Nebula account. .EXAMPLE $accountID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' $clientID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' $clientSecret = '000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB' $NebulaToken = Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret .EXAMPLE $NebulaToken = Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret -Verbose .EXAMPLE Get-NebulaToken -AccountID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientSecret '000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB' #> Param ( [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()] [ValidatePattern('^[{(]?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})[)}]?$')] [string] $AccountID, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidatePattern('^[{(]?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})[)}]?$')] [string] $ClientID, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [ValidatePattern('^[a-f0-9]{64}$')] [string] $ClientSecret, [Parameter(Mandatory=$false)][ValidateNotNullOrEmpty()][ValidateSet('read','write','execute','read write','read execute','write execute','read write execute')] [string] $Scope = 'read write execute', [ValidateNotNullOrEmpty()][Parameter(Mandatory=$false)] [string] $BaseUrl = 'https://api.malwarebytes.com' ) Write-Verbose 'Executing function Get-NebulaToken' Try { $URI = $BaseUrl + '/oauth2/token' Write-Verbose $URI $credential_pair = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(($ClientID, $ClientSecret -join ':'))) [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ 'Authorization' = ('Basic', $credential_pair -join ' '); 'Content-Type' = 'application/x-www-form-urlencoded' } $headers | Select-Object -Property * | Out-String | Write-Verbose $body = @{ scope="$Scope" grant_type='client_credentials' } $body | Format-List | Out-String | Write-Verbose $TokenRequest = Invoke-RestMethod -Method POST -Uri $URI -Body $body -Headers $headers Write-Verbose -Message 'Creating NebulaToken object' $NebulaToken = [PSCustomObject]@{ 'PSTypeName' = 'Nebula.Token' 'accountID' = $AccountID 'access_token' = $TokenRequest.access_token 'expires_in' = $TokenRequest.expires_in 'expires_at' = (Get-Date).AddSeconds($TokenRequest.expires_in) 'headers' = @{ 'Authorization' = 'Bearer ' + $TokenRequest.access_token 'accountid' = $AccountID 'Content-Type' = 'application/json' } 'scope' = $TokenRequest.scope 'token_type' = $TokenRequest.token_type 'baseurl' = $BaseUrl } $NebulaToken | Out-String | Write-Verbose } Catch { Write-Host "The following error occured while obtaining the token from Nebula: $_" $ErrorRecord = $_ $Result = $ErrorRecord.ErrorDetails.Message | ConvertFrom-Json Write-Host $Result Return $ErrorRecord } Return $NebulaToken } function Get-NebulaEndpoint { <# .SYNOPSIS Receive Nebula Endpoints. .DESCRIPTION Returns either all endpoints or a specific endpoint if it's id is provided. .PARAMETER Nebula.Token Can be provided as a parameter or in a pipeline; see .EXAMPLE. .PARAMETER HostName OPTIONAL - Search for endpoint by HostName. .PARAMETER HostName OPTIONAL - Search for endpoint by Alias. .PARAMETER DumpResponse OPTIONAL - Print the entire formatted response to screen. .OUTPUTS Outputs endpoint or endpoints. .EXAMPLE $NebulaToken = Get-NebulaToken -AccountID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientSecret '000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB' Get-NebulaEndpoint -NebulaToken $NebulaToken .EXAMPLE Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret | Get-NebulaEndpoint -HostName 'PC1234' .EXAMPLE Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret | Get-NebulaEndpoint #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [PSTypeName('Nebula.Token')] $NebulaToken, [Parameter(Mandatory = $false)] [string] $HostName, [Parameter(Mandatory = $false)] [string] $Alias, [Parameter()] [switch] $DumpResponse ) Begin { Write-Verbose 'Initializing Get-NebulaEndpoint' # Check if both $HostName and $Alias are provided if ($HostName -and $Alias) { throw "You cannot both -HostName and Alias. Please provide only one." } # Initialize endpoints as an empty array for consistent output $endpoints = @() $body = @{ next_cursor = '' page_size = 2000 } } Process { if (!($HostName -or $Alias)) { Try { $bodyJson = $body | ConvertTo-Json $URI = 'https://api.malwarebytes.com/nebula/v1/endpoints' $next_cursor = $body.next_cursor do { $body.next_cursor = $next_cursor $bodyJson = $body | ConvertTo-Json $request = Invoke-RestMethod -Method POST -Uri $URI -Body $bodyJson -Headers $NebulaToken.Headers $endpoints += $request.endpoints $next_cursor = $request.next_cursor } while ($next_cursor -ne '') } Catch { Write-Error -Message "Error obtaining Endpoints from Nebula: $_" } } elseif ($HostName) { Try { $body = @{"host_name.keyword" = $HostName} | ConvertTo-Json $URI = "https://api.malwarebytes.com/nebula/v1/endpoints" $request = Invoke-RestMethod -Method POST -Uri $URI -Body $body -Headers $NebulaToken.Headers $endpoints = $request } Catch { Write-Error -Message "Error obtaining Endpoint ID $EndpointID from Nebula: $_" } } elseif ($Alias) { Try { $body = @{ "alias" = $Alias } | ConvertTo-Json $URI = "https://api.malwarebytes.com/nebula/v1/endpoints" $request = Invoke-RestMethod -Method POST -Uri $URI -Body $body -Headers $NebulaToken.Headers $endpoints = $request } Catch { Write-Error -Message "Error obtaining Alias $Alias from Nebula: $_" } } } End { if ($DumpResponse) { Write-Host "Dumping Endpoints" # Convert to JSON for each item to ensure consistent detailed output $endpoints | ForEach-Object { $_ | ConvertTo-Json -Depth 5 | Out-Host } } return $endpoints } } function Get-NebulaEvent { <# .SYNOPSIS Receive Nebula Events. .DESCRIPTION Returns either all events within a time frame or events from a specific endpoint if its machine_id is provided. .PARAMETER Nebula.Token Can be provided as a parameter or in a pipeline; see .EXAMPLE. .PARAMETER machine_id OPTIONAL - Search for events for endpoint with machine_id. .PARAMETER OneWeek, OneMonth, ThreeMonths, OneYear OPTIONAL - Time frame of events. .PARAMETER DumpResponse OPTIONAL - Print the entire formatted response to screen. .OUTPUTS Outputs events within the time frame or events for a specified endpoint. .EXAMPLE $NebulaToken = Get-NebulaToken -AccountID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientSecret '000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB' Get-NebulaEvent -NebulaToken $NebulaToken .EXAMPLE Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret | Get-NebulaEvent -machine_id 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' .EXAMPLE Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret | Get-NebulaEvent -OneMonth # Get all events from the last month #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [PSTypeName('Nebula.Token')] $NebulaToken, [Parameter(Mandatory = $false)] [string]$machine_id, [switch]$OneWeek, [switch]$OneMonth, [switch]$ThreeMonths, [switch]$OneYear, [Parameter()] [switch] $DumpResponse ) Begin { Write-Verbose 'Initializing Get-NebulaEvent' # Initialize exclusions as an empty array for consistent output $events = @() $next_cursor = '' $page_size = 2000 # Set the desired page size $useStartDate = $false } Process { # Collect all switches in an array $selectedSwitches = @($OneWeek, $OneMonth, $ThreeMonths, $OneYear) # Check how many switches are set to true $countSelected = ($selectedSwitches | Where-Object { $_ }).Count # Validate: Only allow 0 or 1 switch if ($countSelected -gt 1) { throw "You can specify only one time range option: -OneWeek, -OneMonth, -ThreeMonths, or -OneYear." } switch ($countSelected) { 1 { $useStartDate = $true # Determine which switch was selected if ($OneWeek) { $offset = -7 } if ($OneMonth) { $offset = -30 } if ($ThreeMonths) { $offset = -90 } if ($OneYear) { $offset = -365 } } 0 { $offset = -7 # Default start date of a week ago } } $dateStr = (Get-Date).AddDays($offset).ToString("yyyy-MM-ddTHH:mm:ssZ") Try { $URI = 'https://api.malwarebytes.com/nebula/v1/events' # Start forming the URI with page_size and 'start' if ($useStartDate) { $URI += "?start=$dateStr&page_size=$page_size" } else { $URI += "?page_size=$page_size" } # Add machine_id if it is provided if ($machine_id) { $URI += "&machine_id=$machine_id" } do { # Build the URI correctly with next_cursor if available if ($next_cursor) { $uriWithCursor = "$URI&next_cursor=$next_cursor" } else { $uriWithCursor = $URI } $request = Invoke-RestMethod -Method GET -Uri $uriWithCursor -Headers $NebulaToken.Headers $events += $request.events $next_cursor = $request.next_cursor } while ($next_cursor -ne '') } Catch { Write-Error -Message "Error obtaining Events from Nebula: $_" } } End { if ($DumpResponse) { Write-Host "Dumping Events" # Convert to JSON for each item to ensure consistent detailed output $events | ForEach-Object { $_ | ConvertTo-Json -Depth 5 | Out-Host } } return $events } } # Get an authorization token $auth_token = $NebulaToken = Get-NebulaToken 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientSecret '000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB' # Get information about an endpoint with hostname 'MyHostName' $get_endpoint_response = Get-NebulaEndpoint -NebulaToken $auth_token -HostName 'MyHostName' # Extract the machine_id from the response above; i.e. the machine_id of the endpoint named 'MyHostName' $machine_id = $get_endpoint_response.endpoints[0].machine.id # Get events for the last 7 days (default) for the endpoint with hostname 'MyHostName' Get-NebulaEvent -NebulaToken $auth_token -machine_id $machine_id