Recent Discussions
NOC Rollup Status Dashboards for MSPs
LM doesn't come with it out of the box, so I built the NOC Dashboard I've wanted. It provides high level, at-a-glance health indicators for each of our client environments we manage. This makes a great "big board" for a NOC room or a second screen status board for work from home NOC/Support folks. I do have three examples in this code for ways to filter for specific teams/purposes. This all collapses for ease of reference correctly in Powershell ISE on windows. Line 282 references a dataSource I wrote that counts frequency of specific eventlog events to illustrate potential brute force attempts (CTM are my initials, we tag our scripts to make finding the best source of answers faster in the future - old habit from pen & paper change logs from a previous job). As any screenshots would contain client names, I'm unable to post any screen shots of the results of this, but my current settings for my Main dashboard are (This is the first Dashboard I've made that looks better in UIv4 than 3): ... #!!! These two need to be changed. First is a string, second an integer #!!! See the comment block below for instructions # The first chunk of your company's logicmonitor URL $company = "yourCompanyNameHere" # ID of the group to be used as a source for the NOC widget items $parentGroupID = <parentGroupID> <# Netgain Technology, llc ( https://netgaincloud.com ) 2/26/2024 - Developed by Cole McDonald Disclaimer: Neither Netgain nor Cole McDonald are not responsible for any unexpected results this script may cause in your environment. To deploy this: - COLLECTOR: you will need a collector for scripting, this will be the single applies to target. You may need to increase the script timeout depending on the size of your device deployment. - DASHBOARD: you will need a Dashboard with a NOC widget on it. The name can be whatever you'd like, there will be a name change in the "name" property for the initial array. In the case of the first example here, "NOC - Master" - PARENT GROUP: you will need to identify the ID# of the group you wish to use as the source for the subgroup list and set the $parentGroupID to the appropriate ID# Purpose: Create an auto-updating high level NOC dashboard that can show - Rollup state for a list of client subgroups from our \Clients group - Group Indicators for a specific dataSource - Group indicators for a subset of devices within each group After the API region, there are three separate dashboards referenced to illustrate the 3 methods for using this dataSource. NOTE: my code uses backticks for line continuation. Where possible in my code, each line indicates a single piece of information about the script's algorithm and the first character in each line from a block indicates the line's relationship to the one above it. #> #region Rest API Initialization and Functions # Init variables used in the RESTApi functions $URLBase = "https://$company.logicmonitor.com/santaba/rest" $accessID = "##ApiAccessID.key##" $accessKey = "##ApiAccessKey.key##" #-------- The Functions ---------- function Send-Request { param ( $cred , $URL , $accessid = $null, $accesskey = $null, $data = $null, $version = '3' , $httpVerb = "GET" ) if ( $accessId -eq $null) { exit 1 } <# 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 #> $response = Invoke-RestMethod ` -Uri $URL ` -Method $httpVerb ` -Body $data ` -Header $headers ` -erroraction SilentlyContinue ` -warningaction SilentlyContinue Return $response } function Get-LMRestAPIObjectListing { param ( $URLBase , $resourcePathRoot , # "/device/devices" $size = 1000 , $accessKey , $accessId , $version = '2' ) $output = @() $looping = $true $counter = 0 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 } # Get Dashboards $resourcePath = "/dashboard/dashboards" $dashboards = Get-LMRestAPIObjectListing ` -resourcePathRoot $resourcePath ` -accessKey $accessKey ` -accessId $accessID ` -URLBase $URLBase # Get Widgets $resourcePath = "/dashboard/widgets" $widgets = Get-LMRestAPIObjectListing ` -resourcePathRoot $resourcePath ` -accessKey $accessKey ` -accessId $accessID ` -URLBase $URLBase # Get Groups $resourcePath = "/device/groups" $Groups = Get-LMRestAPIObjectListing ` -resourcePathRoot $resourcePath ` -accessKey $accessKey ` -accessId $accessID ` -URLBase $URLBase #endregion function generateJSON { param( $dashInfo, $clientnames, $deviceDisplayName = "*", $DSDisplayName = "*" ) $itemArray = @() foreach ($name in $clientnames) { $itemArray += @{ "type" = "device" "deviceGroupFullPath" = "Clients/$name" "deviceDisplayName" = $deviceDisplayName "dataSourceDisplayName" = $DSDisplayName "instanceName" = "*" "dataPointName" = "*" "groupBy" = "deviceGroup" "name" = "`#`#RESOURCEGROUP`#`#" } } # Write JSON back to the API for that widget $outputJSON = "`n`t{`n`t`t`"items`" : [`n" foreach ($item in $itemArray) { $elementJSON = @" { `"type`" : `"$($item.type)`", `"dataPointName`" : `"$($item.dataPointName)`", `"instanceName`" : `"$($item.instanceName)`", `"name`" : `"$($item.name)`", `"dataSourceDisplayName`" : `"$($item.dataSourceDisplayName)`", `"groupBy`" : `"$($item.groupBy)`", `"deviceGroupFullPath`" : `"$($item.deviceGroupFullPath)`", `"deviceDisplayName`" : `"$($item.deviceDisplayName)`" } "@ if ($item -ne $itemArray[-1]) { $outputJSON += "$elementJSON,`n" } else { # Last Item $outputJSON += "$elementJSON`n`t`t]`n`t}" } } write-output $outputJSON } # Get Client Names from groups $clientnames = ( $groups ` | where parentid -eq $parentGroupID ` | where name -notmatch "^\." ).name | sort #ID Master Dashboard # declare dashboard name and set default id and widgetid to use in the loop later $masterDash = @{ id=0; widgetid=0; name="NOC - Master" } $master = $dashboards | ? name -eq $masterDash.name if (($master.name).count -eq 1) { $masterDash.id = $master.id $masterDash.widgetid = $master.widgetsConfig[0].psobject.Properties.name $outputJSON = generateJSON ` -dashInfo $masterDash ` -clientnames $clientnames $resourcePath = "/dashboard/widgets/$($masterDash.widgetid)" $url = $URLBase + $resourcePath $widget = Send-Request ` -accessKey $accessKey ` -accessId $accessID ` -data $outputJSON ` -URL $URL ` -httpVerb "PATCH" } #ID Network Dashboard # declare dashboard name and set default id and widgetid to use in the loop later $networkDash = @{ id=0; widgetid=0; name="NOC - Network" } # preset filters for specific dashboard targeting by device $networkDeviceDisplayNameString = "*(meraki|kemp)*" $network = $dashboards | ? name -eq $networkDash.name if (($network.name).count -eq 1) { $networkDash.id = $network.id $networkDash.widgetid = $network.widgetsConfig[0].psobject.Properties.name $outputJSON = generateJSON ` -dashInfo $networkDash ` -clientnames $clientnames ` -deviceDisplayName $networkDeviceDisplayNameString $resourcePath = "/dashboard/widgets/$($networkDash.widgetid)" $url = $URLBase + $resourcePath $widget = Send-Request ` -accessKey $accessKey ` -accessId $accessID ` -data $outputJSON ` -URL $URL ` -httpVerb "PATCH" } #ID Security Dashboard # declare dashboard name and set default id and widgetid to use in the loop later $securityDash = @{ id=0; widgetid=0; name="NOC - Security" } # preset filters for specific dashboard targeting by datasource $securityDataSourceDisplayNameString = "Event Frequency Sec:4625 CTM" $security = $dashboards | ? name -eq $securityDash.name if (($security.name).count -eq 1) { $securityDash.id = $security.id $securityDash.widgetid = $security.widgetsConfig[0].psobject.Properties.name $outputJSON = generateJSON ` -dashInfo $securityDash ` -clientnames $clientnames ` -DSDisplayName $securityDataSourceDisplayNameString $resourcePath = "/dashboard/widgets/$($securityDash.widgetid)" $url = $URLBase + $resourcePath $widget = Send-Request ` -accessKey $accessKey ` -accessId $accessID ` -data $outputJSON ` -URL $URL ` -httpVerb "PATCH" }22Views0likes3CommentsModules for Citrix Cloud/DaaS/VAD monitoring
Hi, here are some modules to monitor Citrix DaaS/VAD via the Citrix Monitor API. These might be helpful with mixture of DaaS and on-prem VAD environments as the same modules can be used for both. Setup details are in the module notes, see the CitrixDaaS_Token notes for the Citrix Cloud API setup. I have made the .xml export of each module available on Github, they can be downloaded from here: https://github.com/chrisred/logicmonitor-citrixdaas The modules are: CitrixDaaS_ApplicationUsage.xml CitrixDaaS_ConnectionFailures.xml CitrixDaaS_DeliveryGroups.xml CitrixDaaS_LogonPerformace.xml CitrixDaaS_Machines.xml CitrixDaaS_Token.xml I'll try to keep an eye on this post for any questions.227Views20likes7CommentsProgrammatic Ping Alert
We currently lack the ability to white list domain names on our firewall, so I have to do everything via IP. Recently I’ve come across an issue where a company won’t give me their external IP’s because they can change, or so they say. For several weeks I’ve pinged the IP’s and it has always been 1 of 4 IPs. Has anyone created some kind of ping alert that does something like “ping easypost.com and api.easypost.com if the IP’s returned are not in 169.62.110.130-169.62.110.133, alert me” I’m not much of a programmer myself so I’d need something pretty “plug and play”. TIA!Solved51Views6likes3CommentsHow to redirect the output of the groovy script to the collector log file using groovy script?
In my groovy script, I want to redirect the output from the groovy script into the collectors log file? What should be the groovy code, to redirect the output to the collectors log file? Can anyone help me here?13Views4likes1CommentCitrix Cloud Monitoring
Installation 1. Install the package from LM Exchange "Citrix Cloud" 2. Install Cloud Connector property source: LocatorJYW9D7 Configuration This datasource requires several properties to be set: CITRIX.CLOUD.CUSTOMER - This is found in the Citrix Cloud Portal:Identity and Access Management > API Access > Secure Clients. Copy the bolded customer ID on the page. CITRIX.CLOUD.ID - Create a secure client, you can name it "LogicMonitor". The ID here will be used for this property. CITRIX.CLOUD.PASS - This is the secret when you created the secure client. CITRIXCLOUD.OAUTH.KEY - This will be autogenerated and populated by LogicMonitor using the above credentials. There is aCitrix CloudOAuth datasource that will generate a bearer token and save it as a property on the device. LM.API.ID -Create an API token in LogicMonitor with administrator privileges, copy the Access ID. LM.API.KEY - This is the API token access key that was created above. LM.API.ACCOUNT - This is your LogicMonitor account name, you can probably copy the subdomain of your LM portal. https://yourco.logicmonitor.com 1. Set the properties above (except CITRIXCLOUD.OAUTH.KEY)wherever you'd like depending on your folder structure. I like to set the LM API propertiesat the root and the Citrix Cloud properties per client (folder). 2. Find your cloud connector device in LM and add the category "PrimaryCC". Make sure you have the Cloud Connector property source installed as well! 3. The OAuth datasource should run, generating a token that the other datasources will use to query Citrix Cloud's API. You can also do a manual "poll now" to speed up the process. You should now see theCITRIXCLOUD.OAUTH.KEY property on the device. If you have any issues, feel free to private message me!1.2KViews37likes46CommentsPrint Spooler
Has anyone been able to get a non-cluster print spooler to work? I’m trying to list out the printers connected to the print spooler so I don’t have to manually maintain an individual printer list and have been unable to get custom scripting to work by adjusting the cluster code. Let me know if anyone has a better way to do this.46Views2likes3CommentsDoes anyone have any experience with monitoring Windows Processes?
I’ve checked the community for datasources and I don’t see anything to what I’m specifically looking for. Our organization currently utilizes the Microsoft_Windows_Services datasource (modified a little bit for our specific needs) to monitor services. I’m looking for something similar to monitor windows processes. Similar to the Microsoft_Windows_Services datasource, what I am hoping to accomplish is provide a list of keywords that will either match or be contained in the process name that I want to monitor, provide a list of machines that I want to monitor those processes on, andthen get alerted on if those processes stop running. Some issues I am running into so far are: Win32_Process always returns a value of NULL for status and state. So I cannot monitor for those two class level properties. Powershell’s Get-Process does not return status or state, rather it just looks for processes that are actively running, so I would need to get creative in having LogicMonitor create the instance and what value to monitor in the instance. Some of the processes I want to monitorcreate multiple processes with the same name, and LogicMonitor then groups them all together into one instance, which makes monitoring diffucult. Some of the process I want to monitor are processes that only run if an application is manually launched, which means that again I will need to get creative in how I set up monitoring because I don’t want to get alerts when a process that I know shouldn’t be running is not running. Because the processes I am trying to monitor are not going to be common for everyone everywhere, something that other people could do to try to replicate my scenario would be: Open Chrome. When Chrome is launched, you will get a processed called “Chrome”. Now, open several other tabs of Chrome, you will just get more processes named “Chrome”. Now, keeping in mind the points I made earlier, set up monitoring to let you know when the 3rd tab in Chrome has been closed, even though the rest of the Chrome tabs arestill open. How would you break that down? My first thought would be to monitor the PIDs, however, when you reboot your machine, your PIDs will likely change. Also, I don’t want to have the datasource wild value search by PID, because that would get confusing really fast once you have 2 or 3 different PIDs that you want to monitor. All suggestions are welcome, and any help is greatly appreciated. Bonus points if you can get this to work with the discovery method as Script and you use an embedded Groovy or Powershell script.Solved277Views12likes19Comments