The PowerShell script below will connect to Datto RMM’s cloud platform, specifically the Merlot API, and close all non-critical alerts older than a specified date. This is all easily configurable and by simply changing the API endpoints should allow you to connect to any of Datto’s available regions.
For information on enabling or configuring the Datto API please refer to the official documentation – https://rmm.datto.com/help/en/Content/2SETUP/APIv2.htm
The Script
When ran, the script will request your API Key and Secret, you should update the ‘siteGuid’, ‘NewestLogToKeep’ and ‘closeCritical’ variables at the top of the script at minimum. You may also want to search the script for “https://merlot-api.centrastage.net” and update it to your own API endpoint which is dependent on the region your Datto instance is located in.
$APIKey = Read-Host "Please enter the API Key"
$APISecretKey = Read-Host "Please enter the Secret Key"
$siteGuid = "d0c3fffb-4df3-4ff2-9ff7-90435eefffff" # The GUID of the site to query
$NewestLogToKeep = "06/07/2022" # Sets the earliest alerts that will be retained
$requestPerMinuteLimit = 500 # Set the number of requests made per minute
$closeCritical = $false # Set to true to also close critical errors
#region Define Functions
#requires -Version 3.0
function New-AemApiAccessToken
{
param
(
[string]$apiUrl,
[string]$apiKey,
[string]$apiSecretKey
)
# Specify security protocols
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
# Convert password to secure string
$securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force
# Define parameters for Invoke-WebRequest cmdlet
$params = @{
Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ('public-client', $securePassword)
Uri = '{0}/auth/oauth/token' -f $apiUrl
Method = 'POST'
ContentType = 'application/x-www-form-urlencoded'
Body = 'grant_type=password&username={0}&password={1}' -f $apiKey, $apiSecretKey
}
# Request access token
try {(Invoke-WebRequest @params | ConvertFrom-Json).access_token}
catch {$_.Exception}
}
function New-AemApiRequest
{
param
(
[string]$apiUrl,
[string]$apiAccessToken,
[string]$apiMethod,
[string]$apiRequest,
[string]$apiRequestBody
)
# Define parameters for Invoke-WebRequest cmdlet
$params = @{
Uri = '{0}/api{1}' -f $apiUrl, $apiRequest
Method = $apiMethod
ContentType = 'application/json'
Headers = @{
'Authorization' = 'Bearer {0}' -f $apiAccessToken
}
}
# Add body to parameters if present
If ($apiRequestBody) {$params.Add('Body',$apiRequestBody)}
# Make request
try {(Invoke-WebRequest @params).Content}
catch{$_.Exception}
}
#endregion
#region Get all Devices
# Define parameters
$requestDevicesparams = @{
apiUrl = 'https://merlot-api.centrastage.net'
apiKey = $APIKey
apiSecretKey = $APISecretKey
apiMethod = 'GET'
apiRequest = '/v2/site/'+$siteGuid+'/devices'
apiRequestBody = ''
}
# Request an OAuth token
$apiAccessToken = New-AemApiAccessToken @requestDevicesparams
# Request all device data from the API
$AllDevices = @()
$Result = New-AemApiRequest @requestDevicesparams -ApiAccessToken $apiAccessToken | ConvertFrom-Json
$AllDevices += $Result.devices
# If there is more paginated data then keep requesting until there's not
$NextPage = $Result.pageDetails.nextPageUrl
while($NextPage -ne $null) {
$newParams = $requestDevicesparams
$newParams.apiRequest = ($NextPage).Substring($NextPage.IndexOf("/v2"), $NextPage.length - $NextPage.IndexOf("/v2"))
$Result = New-AemApiRequest @requestDevicesparams -ApiAccessToken $apiAccessToken | ConvertFrom-Json
$NextPage = $Result.pageDetails.nextPageUrl
$AllDevices += $Result.devices
}
#endregion
$AllAlerts = @()
$currentIndex = 1
foreach($device in $AllDevices) {
#region Get alerts for each device
# Show a nice progress bar
Write-Progress -Id 0 -Activity "Retrieving alerts for all devices" -Status "$currentIndex of $($AllDevices.Count)" -PercentComplete (($currentIndex / $AllDevices.Count) * 100)
$DeviceID = $device.uid
$requestDevicesparams = @{
apiUrl = "https://merlot-api.centrastage.net"
apiKey = $APIKey
apiSecretKey = $APISecretKey
apiMethod = 'GET'
apiRequest = "/v2/device/$($DeviceID)/alerts/open"
apiRequestBody = ''
}
$OpenAlerts = @()
$Request = New-AemApiRequest @requestDevicesparams -ApiAccessToken $apiAccessToken | ConvertFrom-Json
$OpenAlerts += $Request.alerts
$NextPage = $Request.pageDetails.nextPageUrl
while($NextPage -ne $null) {
$newParams = $requestDevicesparams
$newParams.apiRequest = ($NextPage).Substring($NextPage.IndexOf("/v2"), $NextPage.length - $NextPage.IndexOf("/v2"))
$Request = New-AemApiRequest @requestDevicesparams -ApiAccessToken $apiAccessToken | ConvertFrom-Json
$OpenAlerts += $Request.alerts
$NextPage = $Request.pageDetails.nextPageUrl
}
$AllAlerts += $OpenAlerts
Write-Host -ForegroundColor Green "Found $($OpenAlerts.count) open alerts for $($Device.hostname)"
$currentIndex++
#endregion
}
#region Close all alerts that are not critical priority
# Set the current index to 1 (Used for a progress bar)
$currentIndex = 1
$cutoffUnixTimestamp = (New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date -Date $NewestLogToKeep)).TotalMilliseconds # Calculate the cutoff Unix time based on NewestLogToKeep
$pause = 1000/($requestPerMinuteLimit/60) # Calculate the pause between requests
foreach ($alert in $AllAlerts) {
# Show a nice progress bar
Write-Progress -Id 0 -Activity "Closing alerts" -Status "$currentIndex of $($AllAlerts.Count)" -PercentComplete (($currentIndex / $AllAlerts.Count) * 100)
# Filter out any alerts that are critical or that are newer than the cutoff date
if($alert.priority -eq 'Critical' -and !($closeCritical)) {
Write-host -ForegroundColor yellow "Excluded critical alert for $($alert.alertSourceInfo.deviceName)"
} elseif($alert.timestamp -gt $cutoffUnixTimestamp) {
Write-host -ForegroundColor yellow "Excluded alert for $($alert.alertSourceInfo.deviceName) due to timestamp - $($alert.timestamp)"
} else {
$requestDevicesparams = @{
apiUrl = "https://merlot-api.centrastage.net"
apiKey = $APIKey
apiSecretKey = $APISecretKey
apiMethod = 'POST'
apiRequest = "/v2/alert/$($alert.alertUid)/resolve"
apiRequestBody = ''
}
New-AemApiRequest @requestDevicesparams -ApiAccessToken $apiAccessToken
}
$currentIndex++
Start-Sleep -Milliseconds $pause
}
#endregion








Leave a comment