✅ DO
- Use dedicated cmdlets when available
- Validate input locally before sending
- Use
-WhatIffor testing destructive operations - Implement proper error handling
- Add rate limiting for bulk operations
The Invoke-LMAPIRequest cmdlet provides direct access to any LogicMonitor API endpoint while leveraging the module’s authentication, retry logic, and error handling infrastructure.
Invoke-LMAPIRequest -ResourcePath "/endpoint/path" -Method <GET|POST|PATCH|PUT|DELETE> [-Data <hashtable>] [-QueryParams <hashtable>]# Get all devicesInvoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET
# Get a specific device by IDInvoke-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 rulesInvoke-LMAPIRequest -ResourcePath "/setting/alert/rules" -Method GET
# Get escalation chainsInvoke-LMAPIRequest -ResourcePath "/setting/alert/chains" -Method GET# 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# 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 a device (will prompt for confirmation)Invoke-LMAPIRequest -ResourcePath "/device/devices/1234" -Method DELETE
# Delete without confirmationInvoke-LMAPIRequest -ResourcePath "/device/devices/1234" -Method DELETE -Confirm:$false
# Delete an alert ruleInvoke-LMAPIRequest -ResourcePath "/setting/alert/rules/789" -Method DELETE
# Delete a recipient groupInvoke-LMAPIRequest -ResourcePath "/setting/recipientgroups/456" -Method DELETESome newer endpoints require different API versions (check Swagger docs for version requirements):
# Most endpoints use version 3 (default)Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET -Version 3
# Some newer endpoints may require version 4Invoke-LMAPIRequest -ResourcePath "/setting/integrations" -Method GET -Version 4For cases where you need exact control over JSON formatting:
# 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# 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 backupInvoke-LMAPIRequest -ResourcePath "/device/devices/1234/config/configBackup" -Method GET -OutFile "C:\Backups\device-config.txt"Leverage existing format definitions for clean table output:
# Apply LogicMonitor.Device formattingInvoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET -TypeName "LogicMonitor.Device"For large datasets, implement manual pagination:
$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" -CompletedBy default, Invoke-LMAPIRequest returns raw objects. Control formatting as needed:
# Pipe to Format-Table with specific propertiesInvoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET | Format-Table id, name, displayName, status -AutoSize# Select specific propertiesInvoke-LMAPIRequest -ResourcePath "/device/devices" -Method GET | Select-Object id, name, displayName, status# Detailed view of a single itemInvoke-LMAPIRequest -ResourcePath "/device/devices/123" -Method GET | Format-ListUse the -Debug parameter to see detailed request information:
Invoke-LMAPIRequest -ResourcePath "/device/devices" -Method POST -Data $data -DebugDebug output includes:
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}Create reusable wrapper functions for frequently used endpoints:
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}
# UsageGet-LMDeviceByProperty -PropertyName "environment" -PropertyValue "production"# 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}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}
# UsageNew-LMDeviceWithGroups ` -Name "server01.example.com" ` -DisplayName "Production Server 01" ` -CollectorId 5 ` -GroupNames @("Production", "Web Servers", "US-West")This usually means your data structure doesn’t match the API’s expected format.
Solution: Compare with a working dedicated cmdlet using -Debug:
# Run the equivalent cmdlet with -Debug to see the correct payload formatNew-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-LMAPIRequestYou can also check the Swagger API Documentation for the exact schema requirements.
# Increase retry attemptsInvoke-LMAPIRequest -ResourcePath "/endpoint" -Method GET -MaxRetries 10
# Or add manual delays in loopsforeach ($item in $items) { Invoke-LMAPIRequest -ResourcePath "/endpoint/$item" -Method GET Start-Sleep -Milliseconds 500}# Verify you're connectedif (-not $Script:LMAuth.Valid) { Connect-LMAccount -AccessId $id -AccessKey $key -AccountName "company"}✅ DO
-WhatIf for testing destructive operations❌ DON'T
📖 LogicMonitor Swagger API
The official API documentation is your best resource for:
💡 Pro Tip
When building custom requests:
-DebugThis approach ensures your requests match the API’s expectations!
If you find yourself frequently using Invoke-LMAPIRequest for a specific endpoint:
The module is community-driven, and your feedback helps improve it for everyone!