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.2.2KViews54likes29CommentsWindows Services Monitoring with quite a bit more Automation applied
So today we use LM's Microsoft Windows ServicesDataSource to monitor Windows Services. This DS uses Groovy Script and WMI calls under the hood to fetch the service metrics like state, start mode, status, etc... Everything works fine but one of the prerequisites is to go and manually populate the list of Windows services which then the DS parses out as a WILDVALUE variable in the script. You know, go to the device, click on Down Arrow (Manage Resource Options) --> Add Additional Monitoring --> and CHOOSE from the list of Windows Services. Rinse and Repeat and Save. Then the DS goes to work. Well, what if you have a list of over 100 Windows Services you need to add to let's say 20 Windows devices? That would take forever to populate that list manually... That's a problem number 1. Scratch that. This is not really a problem since one can run a PowerShell script (or Groovy Script) to perform this task using undocumented - but working very well - LM API calls. That problem is solved. Next - This list of over 100 Services needs to be *refreshed* every let's say 24 hours to remove nonexistent services and add new ones based on the Regex filter. That's a problem number 2. And again, one can do it programmatically running API calls but this is where I am trying to figure out how to do it. Run my script as a custom PropertySource? I am not really writing Resource Properties, I am updating instance list (Windows Services) within Additional Monitoring on bunch of Resources. Plus PropertySources are applied when ActiveDiscovery is run which is what, every 24 hours? Or should I write custom DataSource that would accomplish this refresh and specify 1 day collection period? Thanks.Solved700Views4likes2CommentsUsing 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.Solved500Views12likes40CommentsUsing 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));Solved499Views3likes7CommentsRetrieving 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#497Views11likes0CommentsTrouble 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?Solved400Views10likes7CommentsUnable 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.300Views4likes3Commentsstring 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!Solved300Views2likes7CommentsAPI 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 Dudgeon298Views1like13CommentsREST API 503 errors
Hello everyone We have been using various PowerShell scripts for years and have never had any problems with them. Now, since last week Monday, we are getting random 503 “server is busy” HTTP errors on some GET queries such as Devices, Device DataSources, Dashboards, etc. There is no recognizable pattern to the errors. Does this problem also occur for others using script automation via the REST API (occurs in V2 and V3)? I have submitted a support request to LM, but progress is slow... Have a nice day everyone Dorian200Views1like15Comments