Logic.Monitor (PowerShell) module
If you're a LogicMonitor user looking to streamline your workflows and automate repetitive tasks, you'll be pleased to know that there's is a PowerShell module available to help you do just that. As a longtime Windows administrator, I've relied on PowerShell as my go-to tool for automating and managing my infrastructure. I've found that the ability to automate tasks through PowerShell not only saves time, but also reduces errors and ensures consistency across the environment. Developed by myself as a personal side project, this module provides a range of cmdlets that can be used to interact with the LogicMonitor API, making it easier than ever to manage your monitoring setup directly from the command line. Whether you're looking to retrieve information about your monitored devices, update alert thresholds, or perform other administrative tasks, this module has you covered. In this post, we'll take a closer look at the features and capabilities of this module, and show you how to get started with using it in your own automation scripts. This project is published in the PowerShell Gallery at https://www.powershellgallery.com/packages/Logic.Monitor/. Installation From PowerShell Gallery: Install-Module -Name "Logic.Monitor" Upgrading: #New releases are published often, to ensure you have the latest version you can run: Update-Module -Name "Logic.Monitor" General Usage: Before you can use on module commands you will need to be connected to a LM portal. To connect your LM portal use the Connect-LMAccount command: Connect-LMAccount -AccessId "lm_access_id" -AccessKey "lm_access_key" -AccountName "lm_portal_prefix_name" Once connected you can then run an appropriate command, a full list of commands available can be found using: Get-Command -Module "Logic.Monitor" To disconnect from an account simply run the Disconnect-LMAccount command: Disconnect-LMAccount Examples: Most Get commands can pull info by id or name to allow for easier retrieval without needing to know the specific resource id. The name parameters in get commands can also accept wildcard values. Get list of devices: #Get all devices Get-LMDevice #Get device via id Get-LMDevice -Id 1 #Get device via hostname Get-LMDevice -Name device.example.com #Get device via displayname/wildcard Get-LMDevice -DisplayName "corp*" Modify a device: #Change device Name,DisplayName,Descrition,Link and set collector assignment Set-LMDevice -Id 1 -DisplayName "New Device Name" -NewName "device.example.com" -Description "Critical Device" -Link "http://device.example.com" -PreferredCollectorId 1 #Add/Update custom properties to a resource and disable alerting Set-LMDevice -Id 1 -Properties @{propname1="value1";propname2="value2"} -DisableAlerting $true ***Using the Name parameter to target a resource during a Set/Remove command will perform an initial get request for you automatically to retrieve the required id. When performing a large amount of changes using id is the preferred method to avoid excessive lookups and avoid any potential API throttling. Remove a device: #Remove device by hostname Remove-LMDevice -Name "device.example.com" -HardDelete $false Send a LM Log Message: Send-LMLogMessage -Message "Hello World!" -resourceMapping @{"system.displayname"="LM-COLL"} -Metadata @{"extra-data"="value";"extra-data2"="value2"} Add a new user to LogicMonitor: New-LMUser -RoleNames @("administrator") -Password "changeme" -FirstName John -LastName Doe -Email jdoe@example.com -Username jdoe@example.com -ForcePasswordChange $true -Phone "5558675309" There are over ~150 cmdlets exposed as part of this module and more are being added each week as I receive feedback internally and from customers. For more details and other examples/code snippets or to contribute you can visit the github repo where this is hosted. Source Repository:https://github.com/stevevillardi/Logic.Monitor Additional Code Examples:https://github.com/stevevillardi/Logic.Monitor/blob/main/EXAMPLES.md Note: This is very much a personal project and not an official LogicMonitor integration. If the concept of a native PowerShell module interest you, I would recommend putting in a feedback request so that the demand can be tracked.1.6KViews50likes29CommentsUsing Postman to create multiple Websites via API & CSV?
Hi, I’m testing out creating websites (or resources) via the API. I have a standard Post working in Postman just fine. However, when I then try to do the same thing via a CSV file in the Runner section, I’m getting 401 Authorization errors. When I look at the data that’s being sent, it looks the same as what’s sent when I run it manually. Is there something special I need to do when running a Post command via the Runner vs the manual Send command? Thanks.Solved407Views12likes40CommentsUsing REST API from ServiceNow Scripting
I would like to use the REST API from ServiceNow but I'm not able to generate the HMAC using the ServiceNow Glide System native class GlideCertificateEncryption(), the resulting values don't match with what I would expect from Python or PowerShell. Are there any ServiceNow developers out there who have managed to call the LogicMonitor REST API from a ServiceNow script?If you have, could anyone share an example script please. var JavaString = Packages.java.lang.String; var key = new JavaString("key"); var message = new JavaString("message"); var keyUTF8 = new JavaString(key.getBytes("UTF8")); var messageUTF8 = new JavaString(message.getBytes("UTF8")); var util = new GlideStringUtil(); var encryption = new GlideCertificateEncryption(); //var mac = encryption.generateMac(util.base64Encode(keyUTF8), "HMACSHA256", messageUTF8); var mac = encryption.generateMac(HexUtil.convertToBase64(keyUTF8 + ""), "HMACSHA256", messageUTF8 + ""); gs.log(mac); gs.log(HexUtil.convertToBase64(mac)); var decoded = util.base64Decode(mac); var utf8Bytes = decoded.getBytes("UTF8"); gs.log(utf8Bytes.length); gs.log(JSON.stringify(utf8Bytes));Solved366Views3likes7CommentsRetrieving data from an external API via a Groovy Scripted module
1) Using Expert mode, define a resource as the hostname of the api in question, i.e. api.someapinamehere.com. For the purposes of this example, I'm going to make a call to worldtimeapi.org for data on the timezone America/Chicago to determine if daylight savings time is in effect. 2) Next, choose an available collector and group (optional) and click save. Note: normally you would also add your api user name (if any) and api token as properties, but in this case, it's not necessary. 2) Next, go to Settings -> LogicModules -> DataSources and click Add -> Datasource 3) Follow the steps below to adjust the DataSource: 4) Insert this script in the text box entitled Groovy Script under Collector Attributes import com.santaba.agent.groovyapi.expect.Expect; import com.santaba.agent.groovyapi.snmp.Snmp; import com.santaba.agent.groovyapi.http.*; import com.santaba.agent.groovyapi.jmx.*; import org.xbill.DNS.*; import groovy.json.*; //Defines host as the name of the resource added, in this case worldtimeapi.org def host = hostProps.get("system.hostname"); //Defines the path to endpoint def endpointUrl = "/api/timezone/America/Chicago" //Defines port. SSL would require 443. def port = 80 //Opens connection def httpClient = HTTP.open(host, port) //Get response def response = httpClient.get(endpointUrl) //Define status code def statusCode = httpClient.getStatusCode() //Close connection httpClient.close() //Extract values or handle error if(statusCode == 200){ response = new JsonSlurper().parseText(httpClient.getResponseBody()) if(response['dst'] == true){ status = 1 println("dstStatus=${status}") } else { status = 0 println("dstStatus=${status}") } } else { println("Your HTTP get request was not successful. StatusCode=${statusCode}") } 5) Add Normal datapoint named dstStatus 6) Save Module 7) You will see data painted in your portal for the device worldtimeapi.org under the name of the DataSource you created. You can learn more about this on this recently updated support doc: https://www.logicmonitor.com/support/terminology-syntax/scripting-support/access-a-website-from-groovy#356Views11likes0CommentsTrouble Authenticating to LogicMonitor REST API from ServiceNow
I am trying to convert a PowerShell script to run from ServiceNow and found “Using REST API from ServiceNow Scripting” from two years ago. Since then, ServiceNow has addedGlideDigest() which, among other things, should allow me to create a message digest from a string using the SHA256 algorithm, with the result being a Base64 string. However, I am getting back: "{"errorMessage":"Authentication failed","errorCode":1401,"errorDetail":null}" The PowerShell script looks like this: [string]$sandboxaccessid = 'abc' [securestring]$sandboxaccesskey = '123' | ConvertTo-SecureString -AsPlainText -Force [string]$AccountName = 'portalname' [int]$Id = 2 $httpVerb = "GET" $resourcePath = "/device/devices/$id" $AllProtocols = [System.Net.SecurityProtocolType]'Tls11,Tls12' [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols $time = (Get-Date).ToUniversalTime() $epoch = [Math]::Round((New-TimeSpan -Start (Get-Date -Date "1/1/1970") -End $time).TotalMilliseconds) $requestVars = $httpVerb + $epoch + $resourcePath $hmac = New-Object System.Security.Cryptography.HMACSHA256 $hmac.Key = [Text.Encoding]::UTF8.GetBytes([System.Runtime.InteropServices.Marshal]::PtrToStringAuto(([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sandboxaccesskey)))) $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars)) $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-' $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower())) $headers = @{ "Authorization" = "LMv1 $sandboxaccessid`:$signature`:$epoch" "Content-Type" = "application/json" "X-Version" = 3 } $url = "https://$AccountName.logicmonitor.com/santaba/rest$resourcePath" $response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers -ErrorAction Stop $resposne And JavaScript looks like this (at the moment): var ACCESS_ID = 'abc'; var ACCESS_KEY = '123'; var ACCOUNT_NAME = 'portalname'; var resourcePath = '/device/devices'; var time = new Date().getTime(); var epoch = Math.round((time - new Date("1/1/1970").getTime())); var id = 2; var requestVars = 'GET' + epoch + resourcePath; // Compute the HMACSHA256 hash using GlideDigest var gd = new GlideDigest(); var signature = gd.getSHA256Base64(ACCESS_KEY, requestVars); // Remove hyphens from the signature signature = signature.replace(/-/g, ''); var token = 'LMv1 ' + ACCESS_ID + ':' + signature + ':' + epoch; var httpRequest = new GlideHTTPRequest('https://' + ACCOUNT_NAME + '.logicmonitor.com/santaba/rest/device/devices/' + id); httpRequest.addHeader('Content-Type', 'application/json'); httpRequest.addHeader('Authorization', token); httpRequest.addHeader('X-Version', '3'); var response = httpRequest.get(); gs.info('Response status code: ' + response.getStatusCode()); gs.info('Devices = ' + response.body); Anyone know how to make this authentication work, without the customerconvertByteArrayToHex() utility?Solved269Views10likes7CommentsUnable to authenticate Rest api with servicenow to get devices
Hi All, I am trying to authenticate in servicenow using script but it is not working. It is throwing an error authentication failed status 401. var ACCESS_ID = '123'; var ACCESS_KEY = 'abc'; var ACCOUNT_NAME = 'test'; var resourcePath = '/device/devices'; var epoch = (new Date()).getTime(); var id = 2; var requestVars = 'GET' + epoch + resourcePath; var HexUtil = { convertByteArrayToHex : function(byteArray) { var hex = ""; byteArray.forEach(function(byteValue) { hex += HexUtil.convertByteToHex(byteValue); }); return hex; }, convertByteToHex : function(b) { var hexChar = ["0", "1", "2", "3", "4", "5", "6", "7","8", "9", "a", "b", "c", "d", "e", "f"]; return hexChar[(b >> 4) & 0x0f] + hexChar[b & 0x0f]; } }; // Compute the HMACSHA256 hash using GlideDigest var key = "key"; key = encodeURIComponent(key); key = GlideStringUtil.base64Encode(key); var msg = "message"; msg = encodeURIComponent(msg); var mac = new GlideCertificateEncryption(); signature = mac.generateMac(requestVars, "HmacSHA256", ACCESS_ID); var bytes = GlideStringUtil.base64DecodeAsBytes(signature); var hex = HexUtil.convertByteArrayToHex(bytes); var hexB64 = GlideStringUtil.base64Encode(hex); var token = 'LMv1 ' + ACCESS_ID + ':' + signature + ':' + epoch; gs.info('Devices = ' +token); var httpRequest = new GlideHTTPRequest('https://' + ACCOUNT_NAME + '.logicmonitor.com/santaba/rest/device/devices'); httpRequest.addHeader('Content-Type', 'application/json'); httpRequest.addHeader('Authorization', token); //httpRequest.addHeader('x-server-version', '3'); var response = httpRequest.getBody(); gs.log(response); Could you please help me on this.252Views4likes3Commentsstring filters in the API (groovy)
In the past I have not had much need of filters in API, and on the rare occasion I have, it has been numeric filters. But for some reason I cannot get string filters to work at all without throwing errors, either 400 responses, or else unexpected character errors. I can do this all day and get results: queryParams = '?offset=' + offset.toString() + '&size=1000&filter=id:1256'; But as soon as I try to make my filter a string filter, I get errors, and I’ve seen both of the following used in various LM docs online, as if they would work, but I just get unexpected string errors: queryParams = '?offset=' + offset.toString() + '&size=1000&filter=status:active'; queryParams = '?offset=' + offset.toString() + '&size=1000&filter=status:”active”'; Basically, I’m pretty sure I’m just not passing in the string value I want for status in a correct way. I’ve literally seen LM documentation of status:active and I’ve seen other examples when they do name~”whatever” but both of these throw errors. I can even test for status being a number (which obviously give no results), and with no filter, I get back everything (I’m doing setting/admins). And I’ve tried every permutation of quotes in double quotes or backslashed quotes or double and triple quotes and double quotes. Because it something NEWBIE-ish I’m doing wrong. When building a url for the API in groovy, is there some specific way to quote up a string value on a filter? //build the request URL resourcePath = "/setting/admins"; //queryParams = "?size=1000&offset=" + offset.toString(); //queryParams = '?offset=' + offset.toString() + '&size=1000&filter=id:1256'; //queryParams = '?offset=' + offset.toString() + '&size=1000&filter=status:1256'; queryParams = '?offset=' + offset.toString() + '&size=1000&filter=status:active'; queryParams = '?offset=' + offset.toString() + '&size=1000&filter=status:”active”'; url = "https://" + account +".logicmonitor.com/santaba/rest" + resourcePath + queryParams; The first 3 commented items work fine (tho the 3rd one has no results obviously because 1256 isnt a valid status) but as soon as I try status:active or status:”active” its game over. What newbie thing am I doing wrong? Thanks in advance. Cheers!Solved220Views2likes7CommentsAPI Method to CLEAR an Alert (toggle off=on Alert Enable)
Hello, We have a need to via API, CLEAR an alert. I don’t see any API Methods to clear an alert. I only see methods to GET or POST a Note/ACK. Can you assist me with what API method we can use to clear (toggle on/off) an alert? Thanks, Darren Dudgeon200Views0likes13Commentsauthentication failing in ServiceNow getting error 1401
Hi Team, I trying to get the devices from the logicmonitor into servicenow, it is throwing an error authentication failed. {"data":null,"errmsg":"Authentication failed","status":1401} I have compared postman and token and below script token everything is perfect. Below is the script. can you please help me where is the mistake. var ACCESS_ID = 'test'; var ACCESS_KEY = 'abc'; var ACCOUNT_NAME = 'cde'; var epoch = (new Date()).getTime(); var id = 2; var resourcePath = '/device/devices'; var data= ''; var requestVars = 'GET' + epoch + resourcePath; var HexUtil = { convertByteArrayToHex : function(byteArray) { var hex = ""; byteArray.forEach(function(byteValue) { hex += HexUtil.convertByteToHex(byteValue); }); return hex; }, convertByteToHex : function(b) { var hexChar = ["0", "1", "2", "3", "4", "5", "6", "7","8", "9", "a", "b", "c", "d", "e", "f"]; return hexChar[(b >> 4) & 0x0f] + hexChar[b & 0x0f]; } }; var key = "lma_Bmz]H_625^5H[EQi9U627pdg}8yy(-56X-hsiL7~e^s)9~56ee+^Mh)i3DKXLODZmNTRhNTUtMDM2MC00ZTY5LTkyNWItZGIwNjZmMDMyZTg5L4kmWbA"; key = encodeURIComponent(key); key = GlideStringUtil.base64Encode(key); var msg = requestVars; msg = encodeURIComponent(msg); var mac = new GlideCertificateEncryption(); signature = mac.generateMac(key, "HmacSHA256", msg); gs.print(signature); // Yes! bp7ym3X//Ft6uuUn1Y/a2y/kLnIZARl2kXNDBl9Y7Uo= var bytes = GlideStringUtil.base64DecodeAsBytes(signature); gs.print(JSON.stringify(bytes)); gs.print(bytes.length); // Yes! [110,-98,-14,-101,117,-1,-4,91,122,-70,-27,39,-43,-113,-38,-37,47,-28,46,114,25,1,25,118,-111,115,67,6,95,88,-19,74] var hex = HexUtil.convertByteArrayToHex(bytes); gs.print(hex); // Yes! 6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a var hexB64 = GlideStringUtil.base64Encode(hex); gs.print(hexB64); var token = 'LMv1 ' + ACCESS_ID + ':' + hexB64 + ':' + epoch; gs.info('Devices = ' +token); var request = new sn_ws.RESTMessageV2(); request.setEndpoint('https://cde.logicmonitor.com/santaba/rest/device/devices'); request.setHttpMethod('GET'); request.setRequestHeader('Authorization', token); //request.setRequestHeader("Accept", "application/json"); request.setRequestHeader("Content-Type", 'application/json'); var response = request.execute(); var responseBody = response.getBody(); var httpStatus = response.getStatusCode(); gs.log("test==="+httpStatus+responseBody); if (httpStatus == 200) { var temJson = JSON.parse(responseBody); var aTA = temJson.data; gs.log("aTA ==="+aTA); } Thank You, Sai.Solved200Views4likes1CommentDevice DataSource Instance datapoint historical data using RestAPI v3
I am having problems getting the RestAPI to return any data regardless the combination of paths, query params, time filters I try using. What am I doing wrong? Here’s my ultimate URL I’ve built for this effort: $ddsiis a successfully retrieved object (DeviceDataSourceInstance) Start and End are from these: [int]$start = get-date (get-date).addMonths(-3) -uformat %s [int]$end = get-date (get-date).addMonths(-3).AddMinutes(5) -uformat %s /device/devices/$($ddsi.deviceid)/devicedatasources/$($ddsi.devicedatasourceid)/data?size=500&offset=0&start=$start&end=$end&datapoints=Capacity,PercentUsed All of the pieces and parts seem to line up with examples I’ve found here and in the LM Docs…it doesn’t error out, but returns nothing. Goal is to get volume capacity metrics from 3 months ago. Where am I going awry here? Everything works up until I add the /data at the end.179Views15likes25Comments