From connectwise-automate
Lists, executes, and retrieves results from ConnectWise Automate scripts (PowerShell, batch, VBScript, shell). Handles parameters, execution history, and script folders.
How this skill is triggered — by the user, by Claude, or both
Slash command
/connectwise-automate:scriptsWhen to use
When listing, executing, passing parameters, and retrieving results. Use when: automate script, automate powershell, automate execute, run script, script execution, script parameters, script results, script history, labtech script, or automate automation.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Scripts in ConnectWise Automate are automation routines that run on managed endpoints. They can be PowerShell, batch files, VBScript, or Automate's native scripting language. This skill covers script listing, execution, parameters, and result retrieval.
Scripts in ConnectWise Automate are automation routines that run on managed endpoints. They can be PowerShell, batch files, VBScript, or Automate's native scripting language. This skill covers script listing, execution, parameters, and result retrieval.
| Type | Extension | Use Case |
|---|---|---|
| Automate Script | Internal | Built-in functions, agent commands |
| PowerShell | .ps1 | Windows automation, complex logic |
| Batch | .bat/.cmd | Simple Windows tasks |
| VBScript | .vbs | Legacy Windows automation |
| Shell | .sh | Linux/macOS automation |
| Mode | Description | Use Case |
|---|---|---|
| Immediate | Run now on target | Ad-hoc tasks |
| Scheduled | Run at specific time | Maintenance |
| On Event | Triggered by alert/monitor | Automated remediation |
| Login/Logout | Run at user session events | User setup |
| Status | Description |
|---|---|
Running | Currently executing |
Completed | Finished successfully |
Failed | Execution error |
Pending | Queued for execution |
Timeout | Exceeded time limit |
Cancelled | Manually stopped |
interface Script {
// Identifiers
ScriptID: number; // Primary key
ScriptGUID: string; // Global unique ID
Name: string; // Script name
// Organization
FolderID: number; // Folder ID
FolderPath: string; // Full folder path
// Script Content
ScriptType: ScriptType; // Type of script
ScriptVersion: number; // Version number
Description: string; // Script description
// Permissions
ClientID: number; // 0 for global, or specific client
LocationID: number; // 0 for all locations
// Parameters
Parameters: ScriptParameter[];
// Metadata
DateCreated: string; // Creation date
DateModified: string; // Last modified
ModifiedBy: string; // Last editor
Enabled: boolean; // Is active
}
type ScriptType = 'Automate' | 'PowerShell' | 'Batch' | 'VBScript' | 'Shell';
interface ScriptParameter {
Name: string; // Parameter name
Type: ParameterType; // Data type
Required: boolean; // Is required
DefaultValue: string; // Default if not provided
Description: string; // Parameter help
Options: string[]; // For dropdown types
}
type ParameterType = 'String' | 'Number' | 'Boolean' | 'Dropdown' | 'Computer' | 'Client';
interface ScriptExecution {
// Identifiers
ExecutionID: number; // Unique execution ID
ScriptID: number; // Script that ran
ComputerID: number; // Target computer
// Status
Status: ExecutionStatus; // Current status
ExitCode: number; // Process exit code
StartTime: string; // When started
EndTime: string; // When finished
Duration: number; // Seconds elapsed
// Results
Output: string; // Script stdout
ErrorOutput: string; // Script stderr
LogOutput: string; // Automate log entries
// Context
TriggeredBy: string; // Who/what initiated
Parameters: Record<string, string>; // Passed parameters
}
type ExecutionStatus = 'Pending' | 'Running' | 'Completed' | 'Failed' | 'Timeout' | 'Cancelled';
GET /cwa/api/v1/Scripts?pageSize=250
Authorization: Bearer {token}
Response:
[
{
"ScriptID": 1001,
"Name": "Clear Temp Files",
"FolderPath": "Maintenance/Disk Cleanup",
"ScriptType": "PowerShell",
"Description": "Clears Windows temporary directories",
"Enabled": true,
"Parameters": [
{
"Name": "days",
"Type": "Number",
"Required": false,
"DefaultValue": "7",
"Description": "Delete files older than X days"
}
]
}
]
GET /cwa/api/v1/Scripts/{scriptID}
Authorization: Bearer {token}
GET /cwa/api/v1/Scripts?condition=FolderID = 5&pageSize=100
Authorization: Bearer {token}
GET /cwa/api/v1/Scripts?condition=Name contains 'cleanup'&pageSize=50
Authorization: Bearer {token}
POST /cwa/api/v1/Computers/{computerID}/Scripts/{scriptID}/Execute
Authorization: Bearer {token}
Content-Type: application/json
{
"Parameters": {
"days": "30",
"path": "C:\\Temp"
}
}
Response:
{
"ExecutionID": 98765,
"Status": "Pending",
"ComputerID": 12345,
"ScriptID": 1001,
"StartTime": "2024-02-15T10:45:00Z"
}
GET /cwa/api/v1/Scripts/Executions/{executionID}
Authorization: Bearer {token}
Response (Running):
{
"ExecutionID": 98765,
"Status": "Running",
"StartTime": "2024-02-15T10:45:00Z",
"Duration": 30
}
Response (Completed):
{
"ExecutionID": 98765,
"Status": "Completed",
"ExitCode": 0,
"StartTime": "2024-02-15T10:45:00Z",
"EndTime": "2024-02-15T10:46:30Z",
"Duration": 90,
"Output": "Deleted 156 files totaling 2.3 GB",
"ErrorOutput": ""
}
POST /cwa/api/v1/Scripts/{scriptID}/Execute
Authorization: Bearer {token}
Content-Type: application/json
{
"ComputerIDs": [12345, 12346, 12347],
"Parameters": {
"days": "30"
}
}
Response:
{
"Executions": [
{ "ExecutionID": 98765, "ComputerID": 12345, "Status": "Pending" },
{ "ExecutionID": 98766, "ComputerID": 12346, "Status": "Pending" },
{ "ExecutionID": 98767, "ComputerID": 12347, "Status": "Pending" }
]
}
GET /cwa/api/v1/Computers/{computerID}/Scripts/Executions?pageSize=50
Authorization: Bearer {token}
GET /cwa/api/v1/Scripts/{scriptID}/Executions?pageSize=50
Authorization: Bearer {token}
async function findScriptByName(client, name) {
const scripts = await client.request(
`/Scripts?condition=Name contains '${name}'&pageSize=50`
);
if (scripts.length === 0) {
return { found: false, suggestions: [] };
}
if (scripts.length === 1) {
return { found: true, script: scripts[0] };
}
return {
found: false,
ambiguous: true,
suggestions: scripts.map(s => ({
name: s.Name,
id: s.ScriptID,
folder: s.FolderPath,
description: s.Description
}))
};
}
async function runScriptAndWait(client, computerId, scriptId, params = {}, options = {}) {
const { timeoutMs = 300000, pollIntervalMs = 5000 } = options;
// Start the script
const execution = await client.request(
`/Computers/${computerId}/Scripts/${scriptId}/Execute`,
{
method: 'POST',
body: JSON.stringify({ Parameters: params })
}
);
const startTime = Date.now();
// Poll for completion
while (true) {
const status = await client.request(
`/Scripts/Executions/${execution.ExecutionID}`
);
if (['Completed', 'Failed', 'Timeout', 'Cancelled'].includes(status.Status)) {
return {
success: status.Status === 'Completed' && status.ExitCode === 0,
execution: status
};
}
// Check timeout
if (Date.now() - startTime > timeoutMs) {
return {
success: false,
execution: status,
error: 'Polling timeout exceeded'
};
}
await sleep(pollIntervalMs);
}
}
async function validateScriptParams(client, scriptId, providedParams) {
const script = await client.request(`/Scripts/${scriptId}`);
const errors = [];
const warnings = [];
for (const param of script.Parameters || []) {
const value = providedParams[param.Name];
// Check required parameters
if (param.Required && !value && !param.DefaultValue) {
errors.push(`Missing required parameter: ${param.Name}`);
continue;
}
// Type validation
if (value) {
switch (param.Type) {
case 'Number':
if (isNaN(Number(value))) {
errors.push(`Parameter ${param.Name} must be a number`);
}
break;
case 'Boolean':
if (!['true', 'false', '1', '0'].includes(value.toLowerCase())) {
errors.push(`Parameter ${param.Name} must be true/false`);
}
break;
case 'Dropdown':
if (param.Options && !param.Options.includes(value)) {
errors.push(`Parameter ${param.Name} must be one of: ${param.Options.join(', ')}`);
}
break;
}
}
}
// Check for unknown parameters
const knownParams = new Set((script.Parameters || []).map(p => p.Name));
for (const provided of Object.keys(providedParams)) {
if (!knownParams.has(provided)) {
warnings.push(`Unknown parameter: ${provided}`);
}
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
async function runScriptOnMultipleComputers(client, scriptId, computerIds, params = {}) {
const batchSize = 50;
const allResults = [];
for (let i = 0; i < computerIds.length; i += batchSize) {
const batch = computerIds.slice(i, i + batchSize);
const response = await client.request(`/Scripts/${scriptId}/Execute`, {
method: 'POST',
body: JSON.stringify({
ComputerIDs: batch,
Parameters: params
})
});
allResults.push(...response.Executions);
// Respect rate limits between batches
if (i + batchSize < computerIds.length) {
await sleep(1000);
}
}
return allResults;
}
async function monitorExecutions(client, executionIds, options = {}) {
const { onUpdate, timeoutMs = 600000, pollIntervalMs = 10000 } = options;
const startTime = Date.now();
const results = new Map();
// Initialize tracking
executionIds.forEach(id => results.set(id, { Status: 'Unknown' }));
while (true) {
let allComplete = true;
for (const executionId of executionIds) {
const current = results.get(executionId);
if (['Completed', 'Failed', 'Timeout', 'Cancelled'].includes(current.Status)) {
continue;
}
try {
const execution = await client.request(
`/Scripts/Executions/${executionId}`
);
results.set(executionId, execution);
if (!['Completed', 'Failed', 'Timeout', 'Cancelled'].includes(execution.Status)) {
allComplete = false;
}
if (onUpdate) {
onUpdate(executionId, execution);
}
} catch (error) {
results.set(executionId, { Status: 'Error', error: error.message });
}
}
if (allComplete) break;
if (Date.now() - startTime > timeoutMs) {
break;
}
await sleep(pollIntervalMs);
}
return Array.from(results.entries()).map(([id, data]) => ({
executionId: id,
...data
}));
}
function summarizeScriptResult(execution) {
return {
executionId: execution.ExecutionID,
script: execution.ScriptName,
computer: execution.ComputerName,
status: execution.Status,
exitCode: execution.ExitCode,
duration: `${execution.Duration}s`,
success: execution.Status === 'Completed' && execution.ExitCode === 0,
output: execution.Output?.substring(0, 1000) || '',
errors: execution.ErrorOutput?.substring(0, 500) || ''
};
}
| Error | Status | Cause | Resolution |
|---|---|---|---|
| Script not found | 404 | Invalid ScriptID | Verify script exists |
| Computer offline | 400 | Target is offline | Wait for computer or schedule |
| Missing parameter | 400 | Required param not provided | Include all required params |
| Permission denied | 403 | No access to script | Check user permissions |
| Execution failed | 400 | Script error | Check script logs |
{
"error": {
"code": "BadRequest",
"message": "Cannot execute script on offline computer"
}
}
async function safeRunScript(client, computerId, scriptId, params = {}) {
// Verify computer is online
const computer = await client.request(`/Computers/${computerId}`);
if (computer.Status !== 'Online') {
return {
success: false,
error: `Computer is ${computer.Status}`,
lastContact: computer.LastContact
};
}
// Validate parameters
const validation = await validateScriptParams(client, scriptId, params);
if (!validation.valid) {
return {
success: false,
error: 'Invalid parameters',
details: validation.errors
};
}
// Execute the script
try {
const execution = await client.request(
`/Computers/${computerId}/Scripts/${scriptId}/Execute`,
{
method: 'POST',
body: JSON.stringify({ Parameters: params })
}
);
return {
success: true,
executionId: execution.ExecutionID,
warnings: validation.warnings
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
| Exit Code | Typical Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Misuse of command |
| 3 | File not found |
| 5 | Access denied |
| 87 | Invalid parameter |
| 1603 | Installation failed |
| -1 | Script exception |
# Script: Clear-TempFiles
# Parameters: days, path
param(
[int]$days = 7,
[string]$path = "$env:TEMP"
)
try {
$cutoff = (Get-Date).AddDays(-$days)
$files = Get-ChildItem -Path $path -Recurse -File |
Where-Object { $_.LastWriteTime -lt $cutoff }
$count = 0
$size = 0
foreach ($file in $files) {
$size += $file.Length
Remove-Item $file.FullName -Force -ErrorAction SilentlyContinue
$count++
}
$sizeGB = [math]::Round($size / 1GB, 2)
Write-Output "Deleted $count files totaling $sizeGB GB"
exit 0
}
catch {
Write-Error $_.Exception.Message
exit 1
}
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin connectwise-automateLists, executes, monitors, and manages automated scripts on assets via SuperOps.ai RMM. Covers script types, execution parameters, scheduling, and result handling for MSP automation.
Authenticates, paginates, filters (OData), and handles errors for the ConnectWise Automate REST API. Covers token management and best practices for integrations.
Manages Datto RMM jobs: running quick jobs, scheduling, monitoring status, viewing results. Covers component scripts, job variables, stdout/stderr, and job lifecycle.