{"article":{"id":35082574965011,"url":"https://mwb-biz.zendesk.com/api/v2/help_center/en-us/articles/35082574965011.json","html_url":"https://support.threatdown.com/hc/en-us/articles/35082574965011-API-Example-Get-endpoints-not-seen-for-more-than-24-hours","author_id":23728246167,"comments_disabled":true,"draft":false,"promoted":false,"position":3,"vote_sum":-1,"vote_count":1,"upvote_count":0,"downvote_count":1,"section_id":4414673418515,"created_at":"2024-11-04T19:52:12Z","updated_at":"2026-08-28T20:42:30Z","name":"API Example - Get endpoints not seen for more than 24 hours","title":"API Example - Get endpoints not seen for more than 24 hours","source_locale":"en-us","locale":"en-us","outdated":false,"outdated_locales":[],"edited_at":"2026-02-02T23:41:23Z","user_segment_id":null,"permission_group_id":156048,"content_tag_ids":[],"label_names":[],"body":"<p>This PowerShell script prints: the site name, the endpoint name, and the hours since last seen for all endpoints that have not been seen in 24 hours or more.</p><p>To use it you should substitute your own OAuth2 Client Credentials at the beginning of the file.</p><h3 id=\"h_01J0CKK8KMDF66Y7RCR33V9ZTA\">Generate client credentials</h3><p>To generate the credentials, log into <a href=\"https://oneview.threatdown.com/auth/login\">OneView</a> and go to <strong>Integrate</strong>.</p><p>For more information on APIs, see OneView API Documentation in the console or hover over the tooltip next to OAuth2 Clients on the Integrate page and click the link.</p><h3 id=\"Find-OfflineEndpoints\">Find-OfflineEndpoints</h3><pre class=\"wysiwyg-code-block\" style=\"line-height: 125%; white-space: pre;\"><code class=\"language-auto\"># Define client_id and client_secret\n$client_id = \"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa\"\n$client_secret = \"000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB\"\n\n# Function to get the token\nfunction Get-Token {\n    param (\n        [string]$client_id,\n        [string]$client_secret\n    )\n\n    # Encode client_id and client_secret to base64\n    $base64EncodedString = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(\"${client_id}:${client_secret}\"))\n\n    # Create headers\n    $headers = @{\n        'Content-Type'  = 'application/x-www-form-urlencoded'\n        'Authorization' = \"Basic $base64EncodedString\"\n    }\n\n    # Create body\n    $body = @{\n        'grant_type' = 'client_credentials'\n        'scope'      = 'read'\n    }\n\n    # Send POST request\n    $response = Invoke-RestMethod -Method Post -Uri 'https://api.malwarebytes.com/oneview/oauth2/token' -Headers $headers -Body $body\n    return $response.access_token\n}\n\n# Function to get sites\nfunction Get-Sites {\n    param (\n        [string]$accessToken\n    )\n\n    try {\n        # Create headers\n        $headers = @{\n            'Content-Type'  = 'application/json'\n            'Authorization' = \"Bearer $accessToken\"\n        }\n\n        # Send GET request\n        $response = Invoke-RestMethod -Method Get -Uri 'https://api.malwarebytes.com/oneview/v1/sites' -Headers $headers\n        return $response\n    } catch {\n        Write-Error \"Error occurred: $_\"\n    }\n}\n\nfunction Get-Endpoints {\n    param (\n        [string]$accessToken,\n        [array]$accountIds,\n        [int]$pageSize,\n        [string]$nextCursor\n    )\n\n    try {\n        # Create headers\n        $headers = @{\n            'Content-Type'  = 'application/json'\n            'Authorization' = \"Bearer $accessToken\"\n        }\n\n        # Create body\n        $body = @{\n            'account_ids' = $accountIds\n            'page_size'   = $pageSize\n            'next_cursor' = $nextCursor\n        } | ConvertTo-Json\n\n        # Send POST request\n        $response = Invoke-RestMethod -Method Post -Uri 'https://api.malwarebytes.com/api/v2/rmm/endpoints' -Headers $headers -Body $body\n        return $response\n    } catch {\n        Write-Error \"Error occurred: $_\"\n    }\n}\n\n# Function to find offline endpoints\nfunction Find-OfflineEndpoints {\n    try {\n        $accessToken = Get-Token -client_id $client_id -client_secret $client_secret\n        $getSitesResponse = Get-Sites -accessToken $accessToken \n\n        # Get all of the defined nebula_account_id's\n        $acctIds = $getSitesResponse.sites | Where-Object { $_.nebula_account_id } | ForEach-Object { $_.nebula_account_id }\n\n        # Call Get-Endpoints with a page_size of 2000 until all pages have been returned\n        $getEndpointsResponse = @{\n            'endpoints' = @()\n        }\n        $epNextCursor = ''\n        do {\n            $epRes = Get-Endpoints -accessToken $accessToken -accountIds $acctIds -pageSize 2000 -nextCursor $epNextCursor\n            $epNextCursor = $epRes.next_cursor\n            $getEndpointsResponse.endpoints += $epRes.endpoints\n        } while ($epNextCursor -ne '')\n\n        # Get all endpoints that haven't been seen in more than 24 hours\n        $now = Get-Date\n        $offlineEndpoints = $getEndpointsResponse.endpoints | Where-Object { -not $_.machine.online } | ForEach-Object {\n            $endpointLastSeen = $null\n            $hoursDifference = $null\n        \n            if ($_.machine.last_seen_at) {\n                try {\n                    $endpointLastSeen = [datetime]::Parse($_.machine.last_seen_at)\n                    $timeDifference = $now - $endpointLastSeen\n                    $hoursDifference = [math]::Truncate($timeDifference.TotalHours)\n                }\n                catch {\n                    Continue # skip this entry if there's an error parsing last_seen_at\n                }\n            }\n            else {\n                Continue # skip if no last_seen_at field\n            }\n        \n            [pscustomobject]@{\n                site                = $_.machine.account.name\n                name                = $_.display_name\n                hoursSinceLastSeen = $hoursDifference\n            }\n        } | Where-Object { $_.hoursSinceLastSeen -gt 24 }\n\n        # Print offline endpoints\n        $offlineEndpoints | ForEach-Object {\n            Write-Output \"Site name: $($_.site) - Endpoint name: $($_.name) - Hours since last seen: $($_.hoursSinceLastSeen)\"\n        }\n    } catch {\n        Write-Error \"Error occurred: $_\"\n    }\n}\n\n# Call the Find-OfflineEndpoints function\nFind-OfflineEndpoints\n</code></pre>","user_segment_ids":[]}}