From kaseya-datto-rmm
Manages Datto RMM devices: lists, searches, monitors endpoints (workstations, servers, ESXi, networks). Covers UIDs, hostnames, MACs, statuses, UDFs, warranty info, operations.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin datto-rmmThis skill uses the workspace's default tool permissions.
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.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides agent creation for Claude Code plugins with file templates, frontmatter specs (name, description, model), triggering examples, system prompts, and best practices.
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
};
}