Cole McDonald

  • Posts

  • Joined

  • Last visited

  • Days Won



15 Good


About Cole McDonald

  • Rank
    Thought Leader
    Thought Leader

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Yeah, I'm using the ID of each bit exclusively. I figured we need the instance IDs as they apply to the specific resource rather than the id of the DS itself... which would be the same for every instance of that DS as applied to any resource. I've built quite a few Relational DB driven apps I've spent my time chasing IDs... and then banging my head against my desk once the "obvious" problem was unconvered. The instance shows the deviceID, the deviceDataSourceID, and the instanceIDs as their own properties in the returned JSON (here parsed into a PSObject). that dds ID should be the specific ID of the DS as applied to that device. Everything seems to be correct on the walk up to the "/data" I'm a little surprised we can't just get "/instance/#####/data" from it as a direct access to the endpoint of the walk since it's a unique ID for the instance itself. Overly complicated data access method that is prone to error and misinterpretation.
  2. I'll be getting postman running tomorrow... my time was up and had to move to another effort. Thank you for pointing the tool out to me. It looks really useful. and thanks for poking at my code. I'll verify I have the right IDs for each of those pieces as well. (Funny Note... I typed this up yesterday and didn't hit submit). I've verified that I have the right pieces and parts. You're examining the JSON in your examples... I use Powershell ISE and explore the return data using the variables. I have verified that I'm using the deviceDataSource rather than the dataSource: PS C:\Users\cole.mcdonald> $inst_CPU id : 8976881 dataSourceId : 5725412 deviceDataSourceId : 427972 groupId : 538636 groupName : @default name : Perfmon_CPU-_Total displayName : _Total description : lockDescription : False deviceId : 5378 and my call was: /device/devices/5378/devicedatasources/427972/instances/8976881/data (I switched devices to verify that it wasn't just empty) I've tried grabbing data from both the instance directly as well as the graph data. I'm going to dig into postman... but looking at it, I don't know that it will necessarily show me anything different than I'm getting using straight powershell... and I generally dislike GUI'd applications for this sort of thing as I find them horribly inefficient (I'm old and grew up on CLI). Here's my Postman return: { "dataSourceName": "Perfmon_CPU", "dataPoints": [ "PercentProcessorTimeCounter", "PercentProcessorTime" ], "values": [], "time": [], "nextPageParams": "" } So it looks like it's succeeding in the call, just no data returned. Odd, because the graph shows that there should be historical data there to grab.
  3. No idea... I've never used it... I've only ever used the PS functions I'm currently using... including to get other data previously. Although I'm not sure if I was using V1 or V2 at that time.
  4. i'm trying to get to this data using Powershell... no errors, it successfully grabs the device, DS, and instances using the same functions... but the data returns an empty array for data that is present in the LM resources interface... thoughts? $resourcePath = "/device/devices/$($$($$($" my output shows me this: Gathering /device/devices/6966/devicedatasources/503122/instances/9311756/data No errors are thrown during the run. It's confounding me a bit.
  5. Here's a bit of PS that goes at the head of my scripts for RESTAPI work... uses Credential Manager 2.0 with the restAPI user/key stored in the windows cred store: Import-Module CredentialManager function Send-Request { param ( $cred , $URL , $accessid = $null, $accesskey = $null, $data = $null, $version = '2' , $httpVerb = "GET" ) if ( $accessId -eq $null) { $accessId = $cred.UserName $accessKey = $cred.GetNetworkCredential().Password } # Use TLS 1.2 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Get current time in milliseconds $epoch = [Math]::Round( ( New-TimeSpan ` -start (Get-Date -Date "1/1/1970") ` -end (Get-Date).ToUniversalTime()).TotalMilliseconds ) # Concatenate Request Details $requestVars = $httpVerb + $epoch + $data + $resourcePath # Construct Signature $hmac = New-Object System.Security.Cryptography.HMACSHA256 $hmac.Key = [Text.Encoding]::UTF8.GetBytes( $accessKey ) $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() ) ) # Construct Headers $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add( "Authorization", $auth ) $headers.Add( "Content-Type" , 'application/json' ) # uses version 2 of the API $headers.Add( "X-version" , $version ) # Make Request try { $response = Invoke-RestMethod ` -Uri $URL ` -Method $httpVerb ` -Body $data ` -Header $headers ` -erroraction stop ` -warningaction SilentlyContinue } catch { $response = -1 } Return $response } function Get-LMRestAPIObjectListing { param ( $URLBase , $resourcePathRoot , # "/device/devices" $size = 1000 , $accessKey , $accessId , $version = '2' ) write-host "Gathering $resourcePathRoot" $output = @() $looping = $true $counter = 0 # write-host "Gathering data from $resourcePathRoot" while ($looping) { # Re-calc offset based on iteration $offset = $counter * $size $resourcePath = $resourcePathRoot $queryParam = "?size=$size&offset=$offset" $url = $URLBase + $resourcePath + $queryParam # Make Request $response = Send-Request ` -accesskey $accessKey ` -accessid $accessId ` -URL $url ` -version $version if ( $response.items.count -eq $size ) { # Return set is full, more items to retrieve $output += $response.items $counter++ } elseif ( $response.items.count -gt 0 ) { # Return set is not full, store date, end loop $output += $response.items $looping = $false } else { # Return set is empty, no data to store, end loop $looping = $false } } write-output $output } $company = "<CompanyName>" $URLBase = "https://$" # This will resolve to proper values if it's being run from inside LM $accessID = "##Logicmonitor.AccessID.key##" $accessKey = "##Logicmonitor.AccessKey.key##" if ( $accessID -like "##*" ) { # Not being run from inside LM - populate manually for testing Import-Module CredentialManager $Cred = Get-StoredCredential -Target LogicMonitor $accessID = $cred.UserName $accessKey = $Cred.GetNetworkCredential().Password } # Get Devices $resourcePath = "/device/devices" $Devices = Get-LMRestAPIObjectListing ` -resourcePathRoot $resourcePath ` -accessKey $accessKey ` -accessId $accessID ` -URLBase $URLBase I wrote most of it using the standard "Send-Request" piece from LM's docs and the posts here... but added a bit to work around the request limit to allow me to fill a variable with all of the specific piece I'm looking for. It also allows for storing creds for dev that are also in LM properties for deployment. They're stored in a generic windows credential named "LogicMonitor" locally. To expand what it does, change or duplicate the "Get Devices" section to target a different $resourcePath from the swagger doc for the restAPI. DISCLAIMER: this code comes with no guarantees from myself or my employers past and present that it is safe in your environment. Use it with caution as you always should.
  6. From the Device perspective, what do the three(?) elements of the sdtstatus mean? Looking at a device, I see "none-none-none" or something like "none-SDT-none" where one of the elements is replaced with SDT. @Sarah Terry?
  7. I've implemented this in the past as a dataSource for tracking number of failed connection attempts against a server over a 5 minute period. Powershell that grabs the last 5 minutes of 4625 from the windows security log where the message contains the status for bad username or bad password. It just returns a count rather than individual events. This let me drive a NOC widget of devices to show brute force intrusion attempts. This could potentially be added like a cluster alert using the existing eventSource though and help to combine individual events into a single actionable alert to reduce noise. This is a super old thread, but I just came across it.... so I'll add my $.02
  8. I'm not sure where it came from. I'm no longer at Beyond Impact, so don't have access to that deployment any longer. I didn't actually perform the deployment of LM at that location, so I'm not sure how it got in the DS list there. It was originally written by an LM developer, but the code above should allow you to create your own implementation of it from scratch.
  9. Thanks guys. Will this allow me to add customProperties or am I locked into accessing existing customProperties?
  10. Has anyone had any success using the v2 of the REST API to push a PATCH to add a customer property to an object (in this case /device/groups/##### without wiping out any other custom properties that have already been set? We've run into a curious behavior while trying to add a property to feed out integration to our ticketing system. It seems to replace the whole of the custom properties object, not just the child object within the customproperties level of the json: { `"customProperties`" : [{ `"name`" : `"connectwisev2.companyid`", `"value`" : `"$($integrationID.TrimEnd())`" }] } We had 2-3 other properties in there that disappeared after patching.
  11. Here's the link: and yes? I don't quite recall how to have it return a NaN, but I have done it in the past, so I know it's possible. unkn() is a constant for it, that may have been how I did it... so: if(maxrtt>100,1,unkn()) ?
  12. If you have a website built that will take a URL structure that can be married to device/instance property values, you can have the alert generate the URL form the inciting instances properties to direct you to the appropriate page. You may need to build out a redirection page within your site that receives and interprets those URLs for you. ##DATASOURCE## might be the right token to use for building that decision/redirection tree.