From datto-rmm
Lists, searches, manages, and monitors Datto RMM endpoints. Covers device identifiers, types, statuses, UDFs, and warranty information.
How this skill is triggered — by the user, by Claude, or both
Slash command
/datto-rmm:devicesWhen to use
When listing, searching, managing, and monitoring endpoints. Use when: datto device, rmm device, device status, device lookup, managed device, device hostname, device online, device offline, endpoint management, or device udf.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Devices are the core managed entities in Datto RMM. Each device represents an endpoint with the Datto agent installed - workstations, servers, ESXi hosts, or network devices. This skill covers device identification, status monitoring, user-defined fields, and common device operations.
Devices are the core managed entities in Datto RMM. Each device represents an endpoint with the Datto agent installed - workstations, servers, ESXi hosts, or network devices. This skill covers device identification, status monitoring, user-defined fields, and common device operations.
Every device has multiple identifiers:
| Identifier | Type | Description | Example |
|---|---|---|---|
deviceUid | string | Globally unique identifier | d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a |
deviceId | integer | Legacy numeric ID | 123456 |
hostname | string | Computer name | ACME-DC01 |
intIpAddress | string | Internal IP address | 192.168.1.100 |
extIpAddress | string | External/public IP | 203.0.113.50 |
macAddresses | array | Network interface MACs | ["00:1A:2B:3C:4D:5E"] |
| Type | Description | Typical Use |
|---|---|---|
Desktop | Workstation/PC | End-user computers |
Laptop | Portable workstation | Mobile workers |
Server | Windows/Linux server | Infrastructure |
ESXi Host | VMware hypervisor | Virtualization |
Network Device | Router/switch/firewall | SNMP-monitored |
Printer | Network printer | Print infrastructure |
| Status | Description | Business Impact |
|---|---|---|
online | Agent checking in | Normal operation |
offline | No agent communication | May require attention |
rebooting | Restart in progress | Temporary state |
unknown | Status undetermined | Check connectivity |
interface Device {
// Identifiers
uid: string; // Unique device ID
deviceId: number; // Legacy numeric ID
hostname: string; // Computer name
description: string; // Custom description
// Site Association
siteUid: string; // Parent site UID
siteName: string; // Site display name
// Type and Status
deviceType: DeviceType; // Desktop, Laptop, Server, etc.
deviceClass: string; // device, esxihost, printer, etc.
status: DeviceStatus; // online, offline, rebooting
// Network
intIpAddress: string; // Internal IP
extIpAddress: string; // External IP
macAddresses: string[]; // MAC addresses
// Operating System
operatingSystem: string; // "Windows 11 Pro"
osType: string; // "Windows", "macOS", "Linux"
osVersion: string; // "10.0.22631"
osSerialNumber: string; // Windows product key
// Hardware
manufacturer: string; // "Dell Inc."
model: string; // "OptiPlex 7090"
serialNumber: string; // Hardware serial
// Agent Info
agentVersion: string; // "2.5.0.1234"
agentPlatform: string; // Platform agent was installed from
// Timestamps (Unix milliseconds)
lastSeen: number; // Last agent check-in
lastReboot: number; // Last system restart
createdAt: number; // When device was added
warrantyExpiry: number; // Warranty end date
// User-Defined Fields
udf1: string; // Custom field 1
udf2: string; // Custom field 2
// ... up to udf30
// Counts
openAlertCount: number; // Active alerts
patchStatus: PatchStatus; // Patch compliance
}
type DeviceType = 'Desktop' | 'Laptop' | 'Server' | 'ESXi Host' | 'Network Device' | 'Printer';
type DeviceStatus = 'online' | 'offline' | 'rebooting' | 'unknown';
Datto RMM provides 30 custom fields per device:
| Field | Type | Max Length | Description |
|---|---|---|---|
udf1 - udf30 | string | 255 chars | Custom data fields |
Common UDF Uses:
udf1: Asset tagudf2: Departmentudf3: Primary userudf4: Location/floorudf5: Purchase dateudf6: Lease expirationGET /api/v2/devices?max=250
Authorization: Bearer {token}
Response:
{
"devices": [
{
"uid": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
"hostname": "ACME-DC01",
"siteUid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"siteName": "Acme Corporation",
"deviceType": "Server",
"status": "online",
"intIpAddress": "192.168.1.10",
"operatingSystem": "Windows Server 2022 Standard",
"lastSeen": 1707991200000,
"openAlertCount": 2
}
],
"pageDetails": {
"count": 250,
"nextPageUrl": "/api/v2/devices?max=250&page=abc123"
}
}
GET /api/v2/device/{deviceUid}
Authorization: Bearer {token}
Response:
{
"uid": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
"hostname": "ACME-DC01",
"description": "Primary Domain Controller",
"siteUid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"siteName": "Acme Corporation",
"deviceType": "Server",
"deviceClass": "device",
"status": "online",
"intIpAddress": "192.168.1.10",
"extIpAddress": "203.0.113.50",
"macAddresses": ["00:1A:2B:3C:4D:5E"],
"operatingSystem": "Windows Server 2022 Standard",
"osVersion": "10.0.20348",
"manufacturer": "Dell Inc.",
"model": "PowerEdge R640",
"serialNumber": "ABC1234567",
"agentVersion": "2.5.0.1234",
"lastSeen": 1707991200000,
"lastReboot": 1707800000000,
"createdAt": 1680000000000,
"warrantyExpiry": 1750000000000,
"udf1": "ASSET-00123",
"udf2": "IT Infrastructure",
"udf3": "John Admin",
"openAlertCount": 2,
"patchStatus": {
"patchesApproved": 5,
"patchesPending": 2,
"patchesFailed": 0
}
}
GET /api/v2/site/{siteUid}/devices?max=250
Authorization: Bearer {token}
POST /api/v2/device/{deviceUid}
Authorization: Bearer {token}
Content-Type: application/json
{
"description": "Updated description",
"udf1": "NEW-ASSET-TAG",
"udf2": "Finance Department"
}
DELETE /api/v2/device/{deviceUid}
Authorization: Bearer {token}
Note: Deleting a device removes it from Datto RMM but does not uninstall the agent.
async function findDeviceByHostname(client, hostname) {
// Fetch all devices (with pagination)
const allDevices = [];
let url = '/api/v2/devices?max=250';
while (url) {
const response = await client.request(url);
allDevices.push(...response.devices);
url = response.pageDetails?.nextPageUrl;
}
// Search case-insensitive
const matches = allDevices.filter(d =>
d.hostname.toLowerCase().includes(hostname.toLowerCase())
);
if (matches.length === 0) {
return { found: false, suggestions: [] };
}
if (matches.length === 1) {
return { found: true, device: matches[0] };
}
return {
found: false,
ambiguous: true,
suggestions: matches.map(d => ({
hostname: d.hostname,
uid: d.uid,
site: d.siteName
}))
};
}
async function findDeviceByIP(client, ipAddress) {
const allDevices = await fetchAllDevices(client);
const device = allDevices.find(d =>
d.intIpAddress === ipAddress || d.extIpAddress === ipAddress
);
return device || null;
}
async function findDeviceByMAC(client, macAddress) {
const normalizedMAC = macAddress.toUpperCase().replace(/[:-]/g, ':');
const allDevices = await fetchAllDevices(client);
const device = allDevices.find(d =>
d.macAddresses?.some(mac =>
mac.toUpperCase().replace(/[:-]/g, ':') === normalizedMAC
)
);
return device || null;
}
async function getOfflineDevices(client, options = {}) {
const {
siteUid,
offlineThresholdMinutes = 30
} = options;
const url = siteUid
? `/api/v2/site/${siteUid}/devices?max=250`
: '/api/v2/devices?max=250';
const allDevices = await fetchAllPaginated(client, url);
const now = Date.now();
const threshold = offlineThresholdMinutes * 60 * 1000;
return allDevices.filter(device => {
if (device.status === 'offline') return true;
if (!device.lastSeen) return true;
// Check if last seen exceeds threshold
return (now - device.lastSeen) > threshold;
}).map(device => ({
hostname: device.hostname,
uid: device.uid,
site: device.siteName,
lastSeen: new Date(device.lastSeen).toISOString(),
offlineMinutes: Math.floor((now - device.lastSeen) / 60000)
}));
}
async function bulkUpdateUDF(client, updates) {
// updates: [{ deviceUid, udf1, udf2, ... }, ...]
const results = [];
for (const update of updates) {
try {
const { deviceUid, ...fields } = update;
await client.request(`/api/v2/device/${deviceUid}`, {
method: 'POST',
body: JSON.stringify(fields)
});
results.push({ deviceUid, success: true });
} catch (error) {
results.push({ deviceUid, success: false, error: error.message });
}
// Respect rate limits
await sleep(100);
}
return results;
}
| Error | Status | Cause | Resolution |
|---|---|---|---|
| Device not found | 404 | Invalid UID | Verify device exists |
| Invalid field value | 400 | UDF too long | Max 255 characters |
| Permission denied | 403 | API key restrictions | Check API permissions |
| Device locked | 409 | Concurrent update | Retry after delay |
{
"errorCode": "DEVICE_NOT_FOUND",
"message": "Device with UID 'd4e5f6a7-...' not found",
"details": {
"deviceUid": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a"
}
}
function validateDeviceUpdate(fields) {
const errors = [];
// Check UDF lengths
for (let i = 1; i <= 30; i++) {
const field = `udf${i}`;
if (fields[field] && fields[field].length > 255) {
errors.push(`${field} exceeds 255 character limit`);
}
}
// Validate description
if (fields.description && fields.description.length > 1000) {
errors.push('Description exceeds 1000 character limit');
}
return {
valid: errors.length === 0,
errors
};
}
nextPageUrlfunction getDeviceEffectiveStatus(device) {
const now = Date.now();
const lastSeenMinutesAgo = (now - device.lastSeen) / 60000;
if (device.status === 'online' && lastSeenMinutesAgo < 15) {
return 'online';
}
if (device.status === 'rebooting') {
return 'rebooting';
}
if (lastSeenMinutesAgo > 60) {
return 'offline';
}
if (lastSeenMinutesAgo > 30) {
return 'stale';
}
return device.status;
}
function getDeviceHealthSummary(device) {
const issues = [];
// Check online status
if (device.status !== 'online') {
issues.push({ severity: 'warning', message: `Device is ${device.status}` });
}
// Check open alerts
if (device.openAlertCount > 0) {
const severity = device.openAlertCount > 5 ? 'critical' : 'warning';
issues.push({
severity,
message: `${device.openAlertCount} open alert(s)`
});
}
// Check patch status
if (device.patchStatus?.patchesFailed > 0) {
issues.push({
severity: 'warning',
message: `${device.patchStatus.patchesFailed} failed patch(es)`
});
}
// Check warranty
if (device.warrantyExpiry && device.warrantyExpiry < Date.now()) {
issues.push({
severity: 'info',
message: 'Warranty expired'
});
}
return {
healthy: issues.length === 0,
issues
};
}
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin datto-rmmInteract with Datto RMM audit data: retrieve hardware, software, network, and system inventories from managed devices.
Lists, searches, and inspects Domotz device inventory. Provides API patterns for device lookup by IP, MAC, or name, plus full site inventory workflows.
Manages NinjaOne devices via API: list, search, manage services, schedule maintenance, reboot, and monitor health for Windows, Mac, and Linux endpoints.