Skip to content

Custom API Requests

Custom API Requests with Invoke-LMAPIRequest

The Invoke-LMAPIRequest cmdlet provides direct access to any LogicMonitor API endpoint while leveraging the module’s authentication, retry logic, and error handling infrastructure.

When to Use This Cmdlet

Basic Syntax

Terminal window
Invoke-LMAPIRequest -ResourcePath "/endpoint/path" -Method <GET|POST|PATCH|PUT|DELETE> [-Data <hashtable>] [-QueryParams <hashtable>]

CRUD Operations

GET - Retrieve Resources

Terminal window
# Get all devices
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET
# Get a specific device by ID
Invoke-LMAPIRequest -ResourcePath "/device/devices/1234" -Method GET
# Get devices with query parameters
$queryParams = @{
size = 500
offset = 0
filter = 'displayName~"prod*"'
fields = "id,name,displayName,currentCollectorId"
sort = "+displayName"
}
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET -QueryParams $queryParams
# Get alert rules
Invoke-LMAPIRequest -ResourcePath "/setting/alert/rules" -Method GET
# Get escalation chains
Invoke-LMAPIRequest -ResourcePath "/setting/alert/chains" -Method GET

POST - Create Resources

Terminal window
# Create a new device (matches New-LMDevice)
$data = @{
name = "server01.example.com"
displayName = "Production Web Server 01"
description = "Primary web server"
preferredCollectorId = 5
hostGroupIds = "2,15,23" # Comma-separated string
disableAlerting = $false
customProperties = @(
@{ name = "environment"; value = "production" }
@{ name = "owner"; value = "ops-team" }
@{ name = "cost.center"; value = "engineering" }
)
}
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method POST -Data $data
# Create a recipient group (matches New-LMRecipientGroup)
$data = @{
groupName = "Operations Team"
description = "Primary ops team notifications"
recipients = @(
@{ type = "ADMIN"; method = "email"; addr = "ops@example.com" }
@{ type = "ADMIN"; method = "sms"; addr = "+15551234567" }
@{ type = "ARBITRARY"; method = "email"; addr = "external@partner.com" }
)
}
Invoke-LMAPIRequest -ResourcePath "/setting/recipientgroups" -Method POST -Data $data

PATCH - Update Resources

Terminal window
# Update device properties (matches Set-LMDevice)
$updates = @{
displayName = "Production Web Server 01 - Updated"
description = "Primary web server - migrated to new datacenter"
disableAlerting = $false
customProperties = @(
@{ name = "environment"; value = "production" }
@{ name = "datacenter"; value = "us-west-2" }
)
}
Invoke-LMAPIRequest -ResourcePath "/device/devices/1234" -Method PATCH -Data $updates
# Update alert rule
$updates = @{
name = "Critical CPU Alert - Updated"
priority = 100
escalatingChainId = 5
}
Invoke-LMAPIRequest -ResourcePath "/setting/alert/rules/789" -Method PATCH -Data $updates

DELETE - Remove Resources

Terminal window
# Delete a device (will prompt for confirmation)
Invoke-LMAPIRequest -ResourcePath "/device/devices/1234" -Method DELETE
# Delete without confirmation
Invoke-LMAPIRequest -ResourcePath "/device/devices/1234" -Method DELETE -Confirm:$false
# Delete an alert rule
Invoke-LMAPIRequest -ResourcePath "/setting/alert/rules/789" -Method DELETE
# Delete a recipient group
Invoke-LMAPIRequest -ResourcePath "/setting/recipientgroups/456" -Method DELETE

Advanced Features

Custom API Versions

Some newer endpoints require different API versions (check Swagger docs for version requirements):

Terminal window
# Most endpoints use version 3 (default)
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET -Version 3
# Some newer endpoints may require version 4
Invoke-LMAPIRequest -ResourcePath "/setting/integrations" -Method GET -Version 4

Raw Body Control

For cases where you need exact control over JSON formatting:

Terminal window
# Useful when you need to preserve null values or specific formatting
$rawJson = @"
{
"name": "test-device",
"displayName": "Test Device",
"preferredCollectorId": 5,
"description": null,
"customProperties": []
}
"@
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method POST -RawBody $rawJson

File Downloads

Terminal window
# Download a report (see /report/reports/{id}/download in Swagger)
Invoke-LMAPIRequest -ResourcePath "/report/reports/123/download" -Method GET -OutFile "C:\Reports\monthly-availability.pdf"
# Download device config backup
Invoke-LMAPIRequest -ResourcePath "/device/devices/1234/config/configBackup" -Method GET -OutFile "C:\Backups\device-config.txt"

Using Existing Format Definitions

Leverage existing format definitions for clean table output:

Terminal window
# Apply LogicMonitor.Device formatting
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET -TypeName "LogicMonitor.Device"

Pagination

For large datasets, implement manual pagination:

Terminal window
$offset = 0
$size = 1000
$allResults = @()
do {
$response = Invoke-LMAPIRequest `
-ResourcePath "/device/devices" `
-Method GET `
-QueryParams @{ size = $size; offset = $offset; sort = "+id" }
$allResults += $response
$offset += $size
Write-Progress -Activity "Fetching devices" -Status "$($allResults.Count) retrieved"
} while ($response.Count -eq $size)
Write-Progress -Activity "Fetching devices" -Completed

Output Formatting

By default, Invoke-LMAPIRequest returns raw objects. Control formatting as needed:

Terminal window
# Pipe to Format-Table with specific properties
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET |
Format-Table id, name, displayName, status -AutoSize

Debugging

Use the -Debug parameter to see detailed request information:

Terminal window
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method POST -Data $data -Debug

Debug output includes:

  • HTTP method and timestamp
  • Parameters used
  • Full endpoint URL
  • Request headers (sensitive data redacted)
  • Complete JSON payload being sent

Error Handling

Terminal window
try {
$result = Invoke-LMAPIRequest `
-ResourcePath "/custom/endpoint" `
-Method POST `
-Data $data `
-ErrorAction Stop
Write-Host "Success: Created resource with ID $($result.id)"
}
catch {
Write-Error "API request failed: $($_.Exception.Message)"
# Implement fallback logic
}

Common Patterns

Pattern 1: Wrapper Functions

Create reusable wrapper functions for frequently used endpoints:

Terminal window
function Get-LMDeviceByProperty {
<#
.SYNOPSIS
Get devices filtered by a custom property
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$PropertyName,
[Parameter(Mandatory)]
[string]$PropertyValue,
[int]$Size = 1000
)
$queryParams = @{
size = $Size
filter = "customProperties.name:`"$PropertyName`",customProperties.value:`"$PropertyValue`""
fields = "id,name,displayName,currentCollectorId"
}
Invoke-LMAPIRequest `
-ResourcePath "/device/devices" `
-Method GET `
-QueryParams $queryParams |
Format-Table id, name, displayName, currentCollectorId -AutoSize
}
# Usage
Get-LMDeviceByProperty -PropertyName "environment" -PropertyValue "production"

Pattern 2: Bulk Operations

Terminal window
# Bulk update device descriptions
$deviceIds = @(1234, 1235, 1236, 1237)
foreach ($id in $deviceIds) {
$updates = @{
description = "Bulk updated on $(Get-Date -Format 'yyyy-MM-dd')"
customProperties = @(
@{ name = "last.update"; value = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') }
)
}
try {
Invoke-LMAPIRequest `
-ResourcePath "/device/devices/$id" `
-Method PATCH `
-Data $updates `
-Confirm:$false
Write-Host "✓ Updated device $id" -ForegroundColor Green
}
catch {
Write-Warning "Failed to update device $id: $_"
}
Start-Sleep -Milliseconds 100 # Rate limiting
}

Pattern 3: Complex Workflows

Terminal window
function New-LMDeviceWithGroups {
<#
.SYNOPSIS
Create a device and add it to multiple groups
#>
param(
[string]$Name,
[string]$DisplayName,
[int]$CollectorId,
[string[]]$GroupNames
)
# Step 1: Get group IDs from names
$groupIds = @()
foreach ($groupName in $GroupNames) {
$group = Invoke-LMAPIRequest `
-ResourcePath "/device/groups" `
-Method GET `
-QueryParams @{ filter = "name:`"$groupName`""; size = 1 }
if ($group) {
$groupIds += $group[0].id
}
}
# Step 2: Create the device
$deviceData = @{
name = $Name
displayName = $DisplayName
preferredCollectorId = $CollectorId
hostGroupIds = ($groupIds -join ",")
customProperties = @(
@{ name = "created.by"; value = "automation" }
@{ name = "created.date"; value = (Get-Date -Format 'yyyy-MM-dd') }
)
}
$device = Invoke-LMAPIRequest `
-ResourcePath "/device/devices" `
-Method POST `
-Data $deviceData
Write-Host "✓ Created device: $($device.displayName) (ID: $($device.id))"
return $device
}
# Usage
New-LMDeviceWithGroups `
-Name "server01.example.com" `
-DisplayName "Production Server 01" `
-CollectorId 5 `
-GroupNames @("Production", "Web Servers", "US-West")

Troubleshooting

”Invalid json body” Errors

This usually means your data structure doesn’t match the API’s expected format.

Solution: Compare with a working dedicated cmdlet using -Debug:

Terminal window
# Run the equivalent cmdlet with -Debug to see the correct payload format
New-LMDevice `
-Name "test.example.com" `
-DisplayName "Test Device" `
-PreferredCollectorId 5 `
-Properties @{ environment = "test"; owner = "ops" } `
-Debug
# The debug output will show:
# DEBUG: Request Payload:
# DEBUG: {
# DEBUG: "name": "test.example.com",
# DEBUG: "displayName": "Test Device",
# DEBUG: "preferredCollectorId": 5,
# DEBUG: "customProperties": [
# DEBUG: {
# DEBUG: "name": "environment",
# DEBUG: "value": "test"
# DEBUG: },
# DEBUG: {
# DEBUG: "name": "owner",
# DEBUG: "value": "ops"
# DEBUG: }
# DEBUG: ],
# DEBUG: "deviceType": 0
# DEBUG: }
# Now you can replicate this structure in Invoke-LMAPIRequest

You can also check the Swagger API Documentation for the exact schema requirements.

Rate Limiting

Terminal window
# Increase retry attempts
Invoke-LMAPIRequest -ResourcePath "/endpoint" -Method GET -MaxRetries 10
# Or add manual delays in loops
foreach ($item in $items) {
Invoke-LMAPIRequest -ResourcePath "/endpoint/$item" -Method GET
Start-Sleep -Milliseconds 500
}

Authentication Errors

Terminal window
# Verify you're connected
if (-not $Script:LMAuth.Valid) {
Connect-LMAccount -AccessId $id -AccessKey $key -AccountName "company"
}

Best Practices

✅ DO

  • Use dedicated cmdlets when available
  • Validate input locally before sending
  • Use -WhatIf for testing destructive operations
  • Implement proper error handling
  • Add rate limiting for bulk operations

❌ DON'T

  • Don’t skip input validation
  • Don’t ignore API documentation
  • Don’t hardcode sensitive data
  • Don’t forget to handle pagination
  • Don’t disable retries without good reason

API Reference

📖 LogicMonitor Swagger API

The official API documentation is your best resource for:

  • Complete endpoint listings
  • Request/response schemas
  • Required vs optional fields
  • API version requirements
  • Authentication details

View Swagger Documentation →

💡 Pro Tip

When building custom requests:

  1. Check Swagger for the endpoint schema
  2. Run a similar dedicated cmdlet with -Debug
  3. Compare the payload formats
  4. Replicate the structure in your request

This approach ensures your requests match the API’s expectations!

Contributing

If you find yourself frequently using Invoke-LMAPIRequest for a specific endpoint:

  1. Open a GitHub issue requesting a dedicated cmdlet
  2. Contribute a PR with the new cmdlet implementation
  3. Share your use case to help prioritize development

The module is community-driven, and your feedback helps improve it for everyone!