This PowerShell script reboots an endpoint whose hostname has been provided.
To use it you should substitute your own OAuth2 Client Credentials at the bottom of the file as well as provide the hostname of the endpoint you want to reboot.
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.
Issue-Reboot
Replace the credentials and hostname with your own credentials and the hostname of the endpoint you want to reboot.
#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 Invoke-NebulaJob { <# .SYNOPSIS Issue a job to an endpoint in Nebula. .DESCRIPTION Issues a job to an endpoint of which the machine_id is supplied. .PARAMETER Nebula.Token Can be provided as a parameter or in a pipeline; see .EXAMPLE. .PARAMETER MachineID machine_id of the endpoint to issue the job on. .PARAMETER DumpResponse OPTIONAL - Print the entire formatted response to screen. .OUTPUTS Outputs endpoint or endpoints. .NOTES The code provided issues a reboot, but you can perform other tasks by replacing the command. Some examples: command.threat.scan - Issue a scan on the target endpoint (machine) command.machine.update.now - Check for software updates See API docs for all commands: https://api.malwarebytes.com/nebula/v1/docs .EXAMPLE $NebulaToken = Get-NebulaToken -AccountID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' -ClientSecret '000000ABCDEF000000ABCDEF000000AB000000ABCDEF000000ABCDEF000000AB' Invoke-NebulaJob -NebulaToken $NebulaToken -MachineID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' .EXAMPLE Get-NebulaToken -AccountID $accountID -ClientID $clientID -ClientSecret $clientSecret | Invoke-NebulaJob -MachineID 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa' #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [PSTypeName('Nebula.Token')] $NebulaToken, [Parameter(Mandatory = $true)] [ValidatePattern('^[{(]?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})[)}]?$')] [string] $MachineID, [Parameter()] [switch] $DumpResponse ) Begin { Write-Verbose 'Initializing Invoke-NebulaJob' $body = @{ machine_ids = @($($MachineID)) command = 'command.asset.reboot' } } Process { Try { $bodyJson = $body | ConvertTo-Json $URI = 'https://api.malwarebytes.com/nebula/v1/jobs' $bodyJson = $body | ConvertTo-Json $request = Invoke-RestMethod -Method POST -Uri $URI -Body $bodyJson -Headers $NebulaToken.Headers } Catch { Write-Error -Message "Error issuing job from Nebula: $_" } } End { if ($DumpResponse) { Write-Host "Dumping Job Response" # Convert to JSON for each item to ensure consistent detailed output $request | ForEach-Object { $_ | ConvertTo-Json -Depth 5 | Out-Host } } return $request } } # Get an authorization token $auth_token = Get-NebulaToken -AccountID '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 # Reboot the endpoint hostname 'MyHostName' Invoke-NebulaJob -NebulaToken $auth_token -MachineID $machine_id