diff --git a/config.json b/config.json
index 00cd76a..5355d3a 100644
--- a/config.json
+++ b/config.json
@@ -1,18 +1,18 @@
{
"name": "ScriptTask",
"shortName": "scripttask",
- "version": "0.0.20",
+ "version": "0.0.21",
"author": "Ryan Blenis",
"description": "Script (PowerShell, BAT, Bash) runner for endpoints",
"hasAdminPanel": false,
"homepage": "https://github.com/ryanblenis/MeshCentral-ScriptTask",
"changelogUrl": "https://raw.githubusercontent.com/ryanblenis/MeshCentral-ScriptTask/master/changelog.md",
- "configUrl": "https://raw.githubusercontent.com/ryanblenis/MeshCentral-ScriptTask/master/config.json",
- "downloadUrl": "https://github.com/ryanblenis/MeshCentral-ScriptTask/archive/master.zip",
+ "configUrl": "https://raw.githubusercontent.com/MrTaravat/MeshCentral-ScriptTask/master/config.json",
+ "downloadUrl": "https://github.com/MrTaravat/MeshCentral-ScriptTask/archive/master.zip",
"repository": {
"type": "git",
- "url": "https://github.com/ryanblenis/MeshCentral-ScriptTask.git"
+ "url": "https://github.com/MrTaravat/MeshCentral-ScriptTask.git"
},
- "versionHistoryUrl": "https://api.github.com/repos/ryanblenis/MeshCentral-ScriptTask/tags",
+ "versionHistoryUrl": "https://api.github.com/repos/MrTaravat/MeshCentral-ScriptTask/tags",
"meshCentralCompat": ">=1.1.35"
-}
\ No newline at end of file
+}
diff --git a/readme.md b/readme.md
index a289b34..da92af8 100644
--- a/readme.md
+++ b/readme.md
@@ -14,7 +14,7 @@ A script running plugin for the [MeshCentral2](https://github.com/Ylianst/MeshCe
Restart your MeshCentral server after making this change.
To install, simply add the plugin configuration URL when prompted:
- `https://raw.githubusercontent.com/ryanblenis/MeshCentral-ScriptTask/master/config.json`
+ `https://raw.githubusercontent.com/MrTaravat/MeshCentral-ScriptTask/master/config.json`
## Features
- Add scripts to a central store
diff --git a/scripttask.js b/scripttask.js
index 609e720..19c4e2d 100644
--- a/scripttask.js
+++ b/scripttask.js
@@ -1,7 +1,7 @@
-/**
+/**
* @description MeshCentral ScriptTask
* @author Ryan Blenis
-* @copyright
+* @copyright
* @license Apache-2.0
*/
@@ -15,31 +15,31 @@ module.exports.scripttask = function (parent) {
obj.intervalTimer = null;
obj.debug = obj.meshServer.debug;
obj.VIEWS = __dirname + '/views/';
- obj.exports = [
+ obj.exports = [
'onDeviceRefreshEnd',
'resizeContent',
'historyData',
'variableData',
'malix_triggerOption'
];
-
+
obj.malix_triggerOption = function(selectElem) {
selectElem.options.add(new Option("ScriptTask - Run Script", "scripttask_runscript"));
}
obj.malix_triggerFields_scripttask_runscript = function() {
-
+
}
obj.resetQueueTimer = function() {
clearTimeout(obj.intervalTimer);
obj.intervalTimer = setInterval(obj.queueRun, 1 * 60 * 1000); // every minute
};
-
+
obj.server_startup = function() {
obj.meshServer.pluginHandler.scripttask_db = require (__dirname + '/db.js').CreateDB(obj.meshServer);
obj.db = obj.meshServer.pluginHandler.scripttask_db;
obj.resetQueueTimer();
};
-
+
obj.onDeviceRefreshEnd = function() {
pluginHandler.registerPluginTab({
tabTitle: 'ScriptTask',
@@ -56,7 +56,7 @@ module.exports.scripttask = function (parent) {
//if (newHeight > 1600) newHeight = 1600;
iFrame.style.height = newHeight + 'px';
};
-
+
obj.queueRun = async function() {
var onlineAgents = Object.keys(obj.meshServer.webserver.wsagents);
//obj.debug('ScriptTask', 'Queue Running', Date().toLocaleString(), 'Online agents: ', onlineAgents);
@@ -66,6 +66,7 @@ module.exports.scripttask = function (parent) {
if (jobs.length == 0) return;
//@TODO check for a large number and use taskLimiter to queue the jobs
jobs.forEach(job => {
+
obj.db.get(job.scriptId)
.then(async (script) => {
script = script[0];
@@ -76,8 +77,8 @@ module.exports.scripttask = function (parent) {
foundVars.forEach(fv => {
foundVarNames.push(fv.replace(/^#+|#+$/g, ''));
});
-
- var limiters = {
+
+ var limiters = {
scriptId: job.scriptId,
nodeId: job.node,
meshId: obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'],
@@ -94,13 +95,13 @@ module.exports.scripttask = function (parent) {
});
replaceVars['GBL:meshId'] = obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'];
replaceVars['GBL:nodeId'] = job.node;
- //console.log('FV IS', finvals);
- //console.log('RV IS', replaceVars);
+ console.log('FV IS', finvals);
+ console.log('RV IS', replaceVars);
}
var dispatchTime = Math.floor(new Date() / 1000);
- var jObj = {
- action: 'plugin',
- plugin: 'scripttask',
+ var jObj = {
+ action: 'plugin',
+ plugin: 'scripttask',
pluginaction: 'triggerJob',
jobId: job._id,
scriptId: job.scriptId,
@@ -109,7 +110,7 @@ module.exports.scripttask = function (parent) {
dispatchTime: dispatchTime
};
//obj.debug('ScriptTask', 'Sending job to agent');
- try {
+ try {
obj.meshServer.webserver.wsagents[job.node].send(JSON.stringify(jObj));
obj.db.update(job._id, { dispatchTime: dispatchTime });
} catch (e) { }
@@ -123,14 +124,14 @@ module.exports.scripttask = function (parent) {
})
.catch(e => { console.log('PLUGIN: ScriptTask: Queue Run Error: ', e); });
};
-
+
obj.cleanHistory = function() {
if (Math.round(Math.random() * 100) == 99) {
//obj.debug('Plugin', 'ScriptTask', 'Running history cleanup');
obj.db.deleteOldHistory();
}
};
-
+
obj.downloadFile = function(req, res, user) {
var id = req.query.dl;
obj.db.get(id)
@@ -143,7 +144,7 @@ module.exports.scripttask = function (parent) {
res.send(file.content);
});
};
-
+
obj.updateFrontEnd = async function(ids){
if (ids.scriptId != null) {
var scriptHistory = null;
@@ -184,9 +185,9 @@ module.exports.scripttask = function (parent) {
});
}
};
-
+
obj.handleAdminReq = function(req, res, user) {
- if ((user.siteadmin & 0xFFFFFFFF) == 1 && req.query.admin == 1)
+ if ((user.siteadmin & 0xFFFFFFFF) == 1 && req.query.admin == 1)
{
// admin wants admin, grant
var vars = {};
@@ -194,15 +195,15 @@ module.exports.scripttask = function (parent) {
return;
} else if (req.query.admin == 1 && (user.siteadmin & 0xFFFFFFFF) == 0) {
// regular user wants admin
- res.sendStatus(401);
+ res.sendStatus(401);
return;
- } else if (req.query.user == 1) {
+ } else if (req.query.user == 1) {
// regular user wants regular access, grant
if (req.query.dl != null) return obj.downloadFile(req, res, user);
var vars = {};
-
+
if (req.query.edit == 1) { // edit script
- if (req.query.id == null) return res.sendStatus(401);
+ if (req.query.id == null) return res.sendStatus(401);
obj.db.get(req.query.id)
.then((scripts) => {
if (scripts[0].filetype == 'proc') {
@@ -235,23 +236,23 @@ module.exports.scripttask = function (parent) {
res.sendFile(__dirname + '/includes/' + req.query.path); // don't freak out. Express covers any path issues.
return;
}
- res.sendStatus(401);
+ res.sendStatus(401);
return;
};
-
+
obj.historyData = function (message) {
if (typeof pluginHandler.scripttask.loadHistory == 'function') pluginHandler.scripttask.loadHistory(message);
if (typeof pluginHandler.scripttask.loadSchedule == 'function') pluginHandler.scripttask.loadSchedule(message);
};
-
+
obj.variableData = function (message) {
if (typeof pluginHandler.scripttask.loadVariables == 'function') pluginHandler.scripttask.loadVariables(message);
};
-
+
obj.determineNextJobTime = function(s) {
var nextTime = null;
var nowTime = Math.floor(new Date() / 1000);
-
+
// special case: we've reached the end of our run
if (s.endAt !== null && s.endAt <= nowTime) {
return nextTime;
@@ -313,7 +314,7 @@ module.exports.scripttask = function (parent) {
case 'weekly':
var tempDate = new Date();
var nowDate = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate());
-
+
if (s.daysOfWeek.length == 0) {
nextTime = null;
break;
@@ -346,7 +347,7 @@ module.exports.scripttask = function (parent) {
var checkDate = baseTime + (86400 * x);
var d = new Date(0); d.setUTCSeconds(checkDate);
var dm = new Date(d.getFullYear(), d.getMonth(), d.getDate());
-
+
console.log('testing date: ', dm.toLocaleString()); // dMidnight.toLocaleString());
//console.log('if break check :', (s.daysOfWeek.indexOf(d.getDay()) !== -1 && checkDate >= nowTime));
//console.log('checkDate vs nowTime: ', (checkDate - nowTime), ' if positive, nowTime is less than checkDate');
@@ -364,52 +365,106 @@ module.exports.scripttask = function (parent) {
nextTime = null;
break;
}
-
+
if (s.endAt != null && nextTime > s.endAt) nextTime = null; // if the next time reaches the bound of the endAt time, nullify
-
+
return nextTime;
};
obj.makeJobsFromSchedules = function(scheduleId) {
- //obj.debug('ScriptTask', 'makeJobsFromSchedules starting');
return obj.db.getSchedulesDueForJob(scheduleId)
- .then(schedules => {
- //obj.debug('ScriptTask', 'Found ' + schedules.length + ' schedules to process. Current time is: ' + Math.floor(new Date() / 1000));
- if (schedules.length) {
- schedules.forEach(s => {
- var nextJobTime = obj.determineNextJobTime(s);
- var nextJobScheduled = false;
- if (nextJobTime === null) {
- //obj.debug('ScriptTask', 'Removing Job Schedule for', JSON.stringify(s));
- obj.db.removeJobSchedule(s._id);
- } else {
- //obj.debug('ScriptTask', 'Scheduling Job for', JSON.stringify(s));
- obj.db.get(s.scriptId)
- .then(scripts => {
- // if a script is scheduled to run, but a previous run hasn't completed,
- // don't schedule another job for the same (device probably offline).
- // results in the minimum jobs running once an agent comes back online.
- return obj.db.getIncompleteJobsForSchedule(s._id)
- .then((jobs) => {
- if (jobs.length > 0) { /* obj.debug('Plugin', 'ScriptTask', 'Skipping job creation'); */ return Promise.resolve(); }
- else { /* obj.debug('Plugin', 'ScriptTask', 'Creating new job'); */ nextJobScheduled = true; return obj.db.addJob( { scriptId: s.scriptId, scriptName: scripts[0].name, node: s.node, runBy: s.scheduledBy, dontQueueUntil: nextJobTime, jobSchedule: s._id } ); }
- });
- })
- .then(() => {
-
- if (nextJobScheduled) { /* obj.debug('Plugin', 'ScriptTask', 'Updating nextRun time'); */ return obj.db.update(s._id, { nextRun: nextJobTime }); }
- else { /* obj.debug('Plugin', 'ScriptTask', 'NOT updating nextRun time'); */ return Promise.resolve(); }
- })
- .then(() => {
- obj.updateFrontEnd( { scriptId: s.scriptId, nodeId: s.node } );
- })
- .catch((e) => { console.log('PLUGIN: ScriptTask: Error managing job schedules: ', e); });
- }
- });
- }
- });
+ .then(schedules => {
+ if (schedules.length > 0) {
+ console.log('PLUGIN DEBUG: Found ' + schedules.length + ' schedules due.');
+
+ schedules.forEach(s => {
+ var nextJobTime = obj.determineNextJobTime(s);
+ var executeImmediatelyTime = nextJobTime ;
+ if (nextJobTime === null) {
+ obj.db.removeJobSchedule(s._id);
+ } else {
+ obj.db.get(s.scriptId)
+ .then(scripts => {
+ if (!scripts || scripts.length === 0) return;
+ var scriptName = scripts[0].name;
+ if (s.node === 'all') {
+ obj.meshServer.db.GetAllType('node', function(err, docs) {
+ if (docs && docs.length > 0) {
+ createJobsForList(docs, s, scriptName, executeImmediatelyTime, nextJobTime);
+ }
+ });
+ }
+
+ else if (typeof s.node === 'string' && s.node.startsWith('mesh/')) {
+ console.log('PLUGIN DEBUG: Schedule is for a MESH (Group):', s.node);
+ obj.meshServer.db.GetAllType('node', function(err, docs) {
+ if (docs && docs.length > 0) {
+ console.log(docs)
+ var meshNodes = docs.filter(function(d) { return d.meshid === s.node; });
+
+ console.log('PLUGIN DEBUG: Nodes found in this group:', meshNodes.length);
+
+ if (meshNodes.length > 0) {
+ createJobsForList(meshNodes, s, scriptName, executeImmediatelyTime, nextJobTime);
+ } else {
+
+ obj.db.update(s._id, { nextRun: nextJobTime });
+ }
+ }
+ });
+ }
+
+ else {
+ return obj.db.getIncompleteJobsForSchedule(s._id)
+ .then((jobs) => {
+ if (jobs.length > 0) { return Promise.resolve(); }
+ else {
+ return obj.db.addJob({
+ scriptId: s.scriptId,
+ scriptName: scriptName,
+ node: s.node,
+ runBy: s.scheduledBy,
+ dontQueueUntil: executeImmediatelyTime,
+ jobSchedule: s._id
+ });
+ }
+ })
+ .then(() => {
+ return obj.db.update(s._id, { nextRun: nextJobTime });
+ })
+ .then(() => {
+ obj.updateFrontEnd( { scriptId: s.scriptId, nodeId: s.node } );
+ });
+ }
+ })
+ .catch((e) => { console.log('PLUGIN Error:', e); });
+ }
+ });
+ }
+ });
};
-
+
+
+ function createJobsForList(nodeList, schedule, scriptName, execTime, nextTime) {
+ var jobProms = [];
+ nodeList.forEach(function(device) {
+ jobProms.push(obj.db.addJob({
+ scriptId: schedule.scriptId,
+ scriptName: scriptName,
+ node: device._id,
+ runBy: schedule.scheduledBy,
+ dontQueueUntil: execTime,
+ jobSchedule: schedule._id
+ }));
+ });
+
+ Promise.all(jobProms).then(() => {
+ console.log('PLUGIN DEBUG: Jobs created for list. Updating next run.');
+ obj.db.update(schedule._id, { nextRun: nextTime });
+ obj.updateFrontEnd({ scriptId: schedule.scriptId });
+ });
+ }
+
obj.deleteElement = function (command) {
var delObj = null;
obj.db.get(command.id)
@@ -436,14 +491,14 @@ module.exports.scripttask = function (parent) {
})
.catch(e => { console.log('PLUGIN: ScriptTask: Error deleting ', e.stack); });
};
-
+
obj.serveraction = function(command, myparent, grandparent) {
switch (command.pluginaction) {
case 'addScript':
obj.db.addScript(command.name, command.content, command.path, command.filetype)
.then(() => {
obj.updateFrontEnd( { tree: true } );
- });
+ });
break;
case 'new':
var parent_path = '';
@@ -539,7 +594,7 @@ module.exports.scripttask = function (parent) {
case 'newFolder':
var parent_path = '';
var new_path = '';
-
+
obj.db.get(command.parent_id)
.then(found => {
if (found.length > 0) {
@@ -564,26 +619,12 @@ module.exports.scripttask = function (parent) {
obj.deleteElement(command);
break;
case 'addScheduledJob':
- /* {
- scriptId: scriptId,
- node: s,
- scheduledBy: myparent.user.name,
- recur: command.recur, // [once, minutes, hourly, daily, weekly, monthly]
- interval: x,
- daysOfWeek: x, // only used for weekly recur val
- // onTheXDay: x, // only used for monthly
- startAt: x,
- endAt: x,
- runCountLimit: x,
- lastRun: x,
- nextRun: x,
- type: "scheduledJob"
- } */
var sj = command.schedule;
-
- var sched = {
- scriptId: command.scriptId,
- node: null,
+ var sel = command.nodes;
+
+ var sObj = {
+ scriptId: command.scriptId,
+ node: null,
scheduledBy: myparent.user.name,
recur: sj.recur,
interval: sj.interval,
@@ -594,25 +635,35 @@ module.exports.scripttask = function (parent) {
nextRun: null,
type: "jobSchedule"
};
- var sel = command.nodes;
+
var proms = [];
- if (Array.isArray(sel)) {
- sel.forEach((s) => {
- var sObj = {...sched, ...{
- node: s
- }};
- proms.push(obj.db.addJobSchedule( sObj ));
- });
- } else { test.push(sObj);
- proms.push(obj.db.addJobSchedule( sObj ));
+
+
+ if (sel === 'all') {
+
+ sObj.node = 'all';
+ proms.push(obj.db.addJobSchedule(sObj));
}
+ else if (Array.isArray(sel)) {
+
+ sel.forEach((s) => {
+ var nodeSched = {...sObj, node: s};
+ proms.push(obj.db.addJobSchedule(nodeSched));
+ });
+ } else {
+
+ sObj.node = sel;
+ proms.push(obj.db.addJobSchedule(sObj));
+ }
+
+
Promise.all(proms)
- .then(() => {
- obj.makeJobsFromSchedules();
- return Promise.resolve();
- })
- .catch(e => { console.log('PLUGIN: ScriptTask: Error adding schedules. The error was: ', e); });
- break;
+ .then(() => {
+ obj.makeJobsFromSchedules();
+ return Promise.resolve();
+ })
+ .catch(e => { console.log('PLUGIN: ScriptTask: Error adding schedules. The error was: ', e); });
+ break;
case 'runScript':
var scriptId = command.scriptId;
var sel = command.nodes;
@@ -641,7 +692,7 @@ module.exports.scripttask = function (parent) {
//obj.debug('ScriptTask', 'getScript Triggered', JSON.stringify(command));
obj.db.get(command.scriptId)
.then(script => {
- myparent.send(JSON.stringify({
+ myparent.send(JSON.stringify({
action: 'plugin',
plugin: 'scripttask',
pluginaction: 'cacheScript',
@@ -707,9 +758,9 @@ module.exports.scripttask = function (parent) {
})
break;
case 'editVar':
- obj.db.update(command.id, {
- name: command.name,
- scope: command.scope,
+ obj.db.update(command.id, {
+ name: command.name,
+ scope: command.scope,
scopeTarget: command.scopeTarget,
value: command.value
})
@@ -728,6 +779,6 @@ module.exports.scripttask = function (parent) {
break;
}
};
-
+
return obj;
}
diff --git a/views/user.handlebars b/views/user.handlebars
index f69a731..336d89c 100644
--- a/views/user.handlebars
+++ b/views/user.handlebars
@@ -13,7 +13,7 @@
width: 100%;
position: absolute;
float:left;*/
-
+
width: 100%;
overflow: hidden;
position: absolute;
@@ -202,7 +202,10 @@
@@ -210,6 +213,7 @@
| Tags |
+
Node Schedules
@@ -244,7 +248,7 @@
[+]
-
+
@@ -258,7 +262,7 @@ var nodesObj = {};
var variables = [];
var varScopes = { global: 'Global', script: 'Script', mesh: 'Mesh', node: 'Node' };
-function onlyUnique(value, index, self) {
+function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
function resizeIframe() {
@@ -287,11 +291,12 @@ function updateNodesTable() {
});
tagList = tagList.filter(onlyUnique); tagList = tagList.sort();
var nodeRowIns = document.querySelector('#mRunTblMesh');
+
for (const i in parent.meshes) { // parent.meshes.forEach(function(i) {
var item = {...parent.meshes[i], ...{}};
if (item.mtype == 2) {
let tpl = `
- |
+ |
`;
nodeRowIns.insertAdjacentHTML('beforeend', tpl);
}
@@ -311,26 +316,17 @@ function selNodesByTag(el) {
var checked = false;
if (el.checked) checked = true;
allNodes.forEach(function(n) {
- if (nodesObj[n.value].tags && nodesObj[n.value].tags.indexOf(t) > -1) n.checked = checked;
- });
- return true;
-}
-function selNodesByMesh(el) {
- var mid = el.value;
- var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
- var checked = false;
- if (el.checked) checked = true;
- allNodes.forEach(function(n) {
- if (nodesObj[n.value].meshid == mid) n.checked = checked;
+ if (nodesObj[n.value].tags && nodesObj[n.value].tags.indexOf(t) > -1) n.checked = checked;
});
return true;
}
+
function selAllNodes(el) {
var allNodes = Q('mRunTbl').querySelectorAll('input[type="checkbox"][name="runOn[]"]');
var checked = false;
if (el.checked) checked = true;
allNodes.forEach(function(n) {
- n.checked = checked;
+ n.checked = checked;
});
return true;
}
@@ -340,7 +336,7 @@ function doOnLoad() {
selectPreviouslySelectedScript();
updateNodesTable();
parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadNodeHistory', 'nodeId': parent.currentNode._id });
- parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadVariables', 'nodeId': parent.currentNode._id });
+ parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadVariables', 'nodeId': parent.currentNode._id });
}
function selectPreviouslySelectedScript() {
@@ -361,13 +357,13 @@ function goRun() {
var scriptId = selScript[0].getAttribute('x-data-id');
if (scriptId == selScript[0].getAttribute('x-folder-id'))
{
- parent.setDialogMode(2, "Oops!", 1, null, 'Please select a script. A folder is currently selected.');
+ parent.setDialogMode(2, "Oops!", 1, null, 'Please select a script. A folder is currently selected.');
}
else {
parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'runScript', 'scriptId': scriptId, 'nodes': [ parent.currentNode._id ], 'currentNodeId': parent.currentNode._id });
}
} else {
- parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
+ parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
}
}
@@ -380,43 +376,66 @@ function goEdit() {
parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'editScript', 'scriptId': sd._id, 'scriptType': sd.type, 'scriptName': sd.name, 'scriptContent': sd.content, 'currentNodeId': parent.currentNode._id });
};
} else {
- parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to edit.');
+ parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to edit.');
}
}
-function goAdvancedRun() {
- var cboxes = document.getElementsByName("runOn[]");
- var sel = [];
-
- cboxes.forEach((n) => {
- if (n.checked) sel.push(n.value);
- });
- if (sel.length == 0) {
- parent.setDialogMode(2, "Oops!", 1, null, 'No machines have been selected.');
- return;
- }
- var selScript = document.querySelectorAll('.liselected');
- if (selScript.length) {
+ function goAdvancedRun() {
+
+ var alls = document.getElementById("all") ? document.getElementById("all").checked : false;
+ var sel = [];
+
+ if (alls) {
+ sel = "all";
+} else {
+ var meshCheckboxes = document.querySelectorAll('#mRunTblMesh input[type="checkbox"]:not(#all)');
+ var selectedMeshIds = [];
+ meshCheckboxes.forEach((box) => {
+ if (box.checked) {
+ sel.push(box.value);
+ selectedMeshIds.push(box.value);
+}
+});
+
+ var nodeCheckboxes = document.getElementsByName("runOn[]");
+ nodeCheckboxes.forEach((n) => {
+ if (n.checked) {
+ var nodeData = nodesObj[n.value];
+ if (nodeData && selectedMeshIds.includes(nodeData.meshid)) {
+} else {
+ sel.push(n.value);
+}
+}
+});
+}
+
+ if (sel.length == 0 && sel !== 'all') {
+ parent.setDialogMode(2, "Oops!", 1, null, 'No machines or groups have been selected.');
+ return;
+}
+
+ var selScript = document.querySelectorAll('.liselected');
+ if (selScript.length) {
var scriptId = selScript[0].getAttribute('x-data-id');
var sWin = window.open('/pluginadmin.ashx?pin=scripttask&user=1&schedule=1', 'schedule', "width=800,height=600");
sWin.scriptId = scriptId;
sWin.nodes = sel;
+
window.schedCallback = function(opts) {
- parent.meshserver.send({
- 'action': 'plugin',
- 'plugin': 'scripttask',
- 'pluginaction': 'addScheduledJob',
- 'scriptId': opts.scriptId,
- 'nodes': opts.nodes,
- 'currentNodeId': parent.currentNode._id,
- 'schedule': opts
- });
- };
- } else {
- parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected to run on the machines.');
- }
+ parent.meshserver.send({
+ 'action': 'plugin',
+ 'plugin': 'scripttask',
+ 'pluginaction': 'addScheduledJob',
+ 'scriptId': opts.scriptId,
+ 'nodes': opts.nodes,
+ 'currentNodeId': parent.currentNode._id,
+ 'schedule': opts
+});
+};
+} else {
+ parent.setDialogMode(2, "Oops!", 1, null, 'No script has been selected.');
+}
}
-
var coll = document.getElementsByClassName("infoBar");
for (var i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
@@ -449,7 +468,7 @@ function addScript(name, content, path) {
parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'addScript', name: name, content: content, path: path, filetype: n });
}
else {
- parent.setDialogMode(2, "Oops!", 1, null, 'Currently accepted filetypes are .ps1, .bat, and bash scripts.');
+ parent.setDialogMode(2, "Oops!", 1, null, 'Currently accepted filetypes are .ps1, .bat, and bash scripts.');
}
}
function redrawScriptTree() {
@@ -498,20 +517,20 @@ function redrawScriptTree() {
parent.pluginHandler.scripttask.loadHistory = function(message) {
// cache script names
var nNames = {};
- parent.nodes.forEach(function(n){
- nNames[n._id] = n.name;
+ parent.nodes.forEach(function(n){
+ nNames[n._id] = n.name;
});
if (message.event.nodeHistory != null && message.event.nodeId == parent.currentNode._id) {
var nHistTbl = document.getElementById('nHistTbl');
var rows = nHistTbl.querySelectorAll('.stNHRow');
if (rows.length) {
rows.forEach(function(r) {
- r.parentNode.removeChild(r);
+ r.parentNode.removeChild(r);
});
}
if (message.event.nodeHistory.length) {
message.event.nodeHistory.forEach(function(nh) {
- nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
+ nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
});
message.event.nodeHistory.sort((a, b) => (a.latestTime < b.latestTime) ? 1 : -1);
message.event.nodeHistory.forEach(function(nh) {
@@ -534,12 +553,12 @@ function redrawScriptTree() {
var rows = sHistTbl.querySelectorAll('.stSHRow');
if (rows.length) {
rows.forEach(function(r) {
- r.parentNode.removeChild(r);
+ r.parentNode.removeChild(r);
});
}
if (message.event.scriptHistory.length) {
message.event.scriptHistory.forEach(function(nh) {
- nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
+ nh.latestTime = Math.max(nh.completeTime, nh.queueTime, nh.dispatchTime, nh.dontQueueUntil);
});
message.event.scriptHistory.sort((a, b) => (a.latestTime < b.latestTime) ? 1 : -1);
message.event.scriptHistory.forEach(function(nh) {
@@ -567,7 +586,7 @@ function redrawScriptTree() {
if (nh.dispatchTime != null) nh.statusTxt = 'Running';
if (nh.errorVal != null) nh.statusTxt = 'Error';
if (nh.returnVal != null) nh.statusTxt = 'Completed';
- if (nh.dontQueueUntil > nowTime) nh.statusTxt = 'Scheduled';
+ if (nh.dontQueueUntil > nowTime) nh.statusTxt = 'Scheduled';
if (nh.returnTxt == null) nh.returnTxt = ' ';
if (nh.statusTxt == 'Completed') {
nh.statusTxt = '' + nh.statusTxt + '';
@@ -617,7 +636,7 @@ function redrawScriptTree() {
})
var ordering = { 'global': 0, 'script': 1, 'mesh': 2, 'node': 3 }
vars.sort((a, b) => {
- return (ordering[a.scope] - ordering[b.scope])
+ return (ordering[a.scope] - ordering[b.scope])
|| a.name.localeCompare(b.name)
|| a.scopeTargetTxt.localeCompare(b.scopeTargetTxt);
});
@@ -628,10 +647,10 @@ function redrawScriptTree() {
function parseVariables() {
var vTbl = document.getElementById('varTbl');
var rows = vTbl.querySelectorAll('.stVRow');
-
+
if (rows.length) {
rows.forEach(function(r) {
- r.parentNode.removeChild(r);
+ r.parentNode.removeChild(r);
});
}
var scriptEl = document.querySelectorAll('.liselected');
@@ -654,27 +673,25 @@ function redrawScriptTree() {
tr.setAttribute('x-data-id', vd._id);
})
}
- parent.pluginHandler.scripttask.loadSchedule = function(message) {
- // cache script names
- var nNames = {}, sNames = {};
- parent.nodes.forEach(function(n){
- nNames[n._id] = n.name;
- });
- scriptTree.forEach(function(s) {
- if (s.type == 'script') sNames[s._id] = s.name;
- });
- if (message.event.nodeSchedule != null && message.event.nodeId == parent.currentNode._id) {
- var nTbl = document.getElementById('nSchTbl');
- var rows = nTbl.querySelectorAll('.stNSRow');
- if (rows.length) {
- rows.forEach(function(r) {
- r.parentNode.removeChild(r);
- });
- }
- if (message.event.nodeSchedule.length) {
- message.event.nodeSchedule.forEach(function(nh) {
- nh = prepSchedule(nh);
- let tpl = '' + sNames[nh.scriptId] + ' | \
+ parent.pluginHandler.scripttask.loadSchedule = function(message) {
+ var nNames = {}, sNames = {};
+ parent.nodes.forEach(function(n){
+ nNames[n._id] = n.name;
+});
+ scriptTree.forEach(function(s) {
+ if (s.type == 'script') sNames[s._id] = s.name;
+});
+
+ if (message.event.nodeSchedule != null && message.event.nodeId == parent.currentNode._id) {
+ var nTbl = document.getElementById('nSchTbl');
+ var rows = nTbl.querySelectorAll('.stNSRow');
+ if (rows.length) {
+ rows.forEach(function(r) { r.parentNode.removeChild(r); });
+}
+ if (message.event.nodeSchedule.length) {
+ message.event.nodeSchedule.forEach(function(nh) {
+ nh = prepSchedule(nh);
+ let tpl = '' + sNames[nh.scriptId] + ' | \
' + nh.scheduledBy + ' | \
' + nh.everyTxt + ' | \
' + nh.startedTxt + ' | \
@@ -682,27 +699,43 @@ function redrawScriptTree() {
' + nh.lastRunTxt + ' | \
' + nh.nextRunTxt + ' | \
' + nh.actionTxt + ' | ';
- let tr = nTbl.insertRow(-1);
- tr.innerHTML = tpl;
- tr.classList.add('stNSRow');
- tr.setAttribute('x-data-id', nh._id);
- });
- }
- }
- var currentScript = document.getElementById('scriptHistory');
- var currentScriptId = currentScript.getAttribute('x-data-id');
- if (message.event.scriptSchedule != null && message.event.scriptId == currentScriptId) {
- var sTbl = document.getElementById('sSchTbl');
- var rows = sTbl.querySelectorAll('.stSSRow');
- if (rows.length) {
- rows.forEach(function(r) {
- r.parentNode.removeChild(r);
- });
- }
- if (message.event.scriptSchedule.length) {
- message.event.scriptSchedule.forEach(function(nh) {
- nh = prepSchedule(nh);
- let tpl = '' + nNames[nh.node] + ' | \
+ let tr = nTbl.insertRow(-1);
+ tr.innerHTML = tpl;
+ tr.classList.add('stNSRow');
+ tr.setAttribute('x-data-id', nh._id);
+});
+}
+}
+
+ var currentScript = document.getElementById('scriptHistory');
+ var currentScriptId = currentScript.getAttribute('x-data-id');
+ if (message.event.scriptSchedule != null && message.event.scriptId == currentScriptId) {
+ var sTbl = document.getElementById('sSchTbl');
+ var rows = sTbl.querySelectorAll('.stSSRow');
+ if (rows.length) {
+ rows.forEach(function(r) { r.parentNode.removeChild(r); });
+}
+ if (message.event.scriptSchedule.length) {
+ message.event.scriptSchedule.forEach(function(nh) {
+ nh = prepSchedule(nh);
+
+ var displayName = '';
+
+ if (nh.node === 'all') {
+ displayName = 'All Devices';
+}
+ else if (typeof nh.node === 'string' && nh.node.startsWith('mesh/')) {
+ if (parent.meshes[nh.node]) {
+ displayName = 'Group: ' + parent.meshes[nh.node].name + '';
+} else {
+ displayName = 'Unknown Group';
+}
+}
+ else {
+ displayName = nNames[nh.node] || 'Unknown Node';
+}
+
+ let tpl = '' + displayName + ' | \
' + nh.scheduledBy + ' | \
' + nh.everyTxt + ' | \
' + nh.startedTxt + ' | \
@@ -710,15 +743,15 @@ function redrawScriptTree() {
' + nh.lastRunTxt + ' | \
' + nh.nextRunTxt + ' | \
' + nh.actionTxt + ' | ';
- let tr = sTbl.insertRow(-1);
- tr.innerHTML = tpl;
- tr.classList.add('stSSRow');
- tr.setAttribute('x-data-id', nh._id);
- });
- }
- }
- resizeIframe();
- }
+ let tr = sTbl.insertRow(-1);
+ tr.innerHTML = tpl;
+ tr.classList.add('stSSRow');
+ tr.setAttribute('x-data-id', nh._id);
+});
+}
+}
+ resizeIframe();
+}
function prepSchedule(nh) {
nh.everyTxt = nh.interval + ' ';
switch (nh.recur) {
@@ -742,7 +775,7 @@ function redrawScriptTree() {
break;
}
if (nh.interval > 1) nh.everyTxt += 's';
-
+
if (nh.recur == 'weekly') {
nh.daysOfWeek = nh.daysOfWeek.map(el => Number(el));
nh.everyTxt += ' (';
@@ -759,7 +792,7 @@ function redrawScriptTree() {
});
nh.everyTxt += ')';
}
-
+
var d = new Date(0); d.setUTCSeconds(nh.startAt);
nh.startedTxt = d.toLocaleString();
d = new Date(0); d.setUTCSeconds(nh.endAt);
@@ -773,7 +806,7 @@ function redrawScriptTree() {
nh.nextRunTxt = d.toLocaleString();
if (nh.nextRun == null) nh.nextRunTxt = 'Never';
if (nh.nextRun < nh.lastRun) nh.nextRunTxt = 'Running now';
-
+
nh.actionTxt = 'Delete';
return nh;
}
@@ -787,7 +820,7 @@ function redrawScriptTree() {
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
- return "in " + hDisplay + mDisplay + sDisplay;
+ return "in " + hDisplay + mDisplay + sDisplay;
}
function isJsonString(str) {
try {
@@ -816,7 +849,7 @@ function redrawScriptTree() {
}
function newVar() {
- parent.setDialogMode(2, "New Variable", 3, newVarEx, 'Variable Name:
Scope:
Value: ');
+ parent.setDialogMode(2, "New Variable", 3, newVarEx, 'Variable Name:
Scope:
Value: ');
parent.focusTextBox('stvarname');
}
function editVarEx() {
@@ -846,7 +879,7 @@ function redrawScriptTree() {
if (v.scope == k) soptHtml += ' selected';
soptHtml += '>' + t + '';
}
- parent.setDialogMode(2, "Edit Variable", 3, editVarEx, 'Variable Name:
Scope:
Value: ');
+ parent.setDialogMode(2, "Edit Variable", 3, editVarEx, 'Variable Name:
Scope:
Value: ');
parent.focusTextBox('stvarname');
}
function delVarEx() {
@@ -857,7 +890,7 @@ function redrawScriptTree() {
function delVar(el) {
var vid = el.parentNode.parentNode.getAttribute('x-data-id');
var v = variables.filter(obj => { return obj._id === vid })[0];
- parent.setDialogMode(2, "Delete Variable", 3, delVarEx, 'Are you sure you want to delete this?
Name: '+ v.name +'
Scope: '+ varScopes[v.scope] +'
Value: '+ v.value);
+ parent.setDialogMode(2, "Delete Variable", 3, delVarEx, 'Are you sure you want to delete this?
Name: '+ v.name +'
Scope: '+ varScopes[v.scope] +'
Value: '+ v.value);
}
function renameEx() {
var name = parent.document.getElementById('stfilename').value;
@@ -870,7 +903,7 @@ function redrawScriptTree() {
var el = scriptEl[0];
var name = el.querySelector('.fname').innerHTML;
var id = el.getAttribute('x-data-id');
- parent.setDialogMode(2, "Rename " + name, 3, renameEx, '');
+ parent.setDialogMode(2, "Rename " + name, 3, renameEx, '');
parent.focusTextBox('stfilename');
}
function newEx() {
@@ -886,7 +919,7 @@ function redrawScriptTree() {
var el = scriptEl[0];
folder_id = el.getAttribute('x-data-folder');
}
- parent.setDialogMode(2, "New Script", 3, newEx, 'Name:
Type:');
+ parent.setDialogMode(2, "New Script", 3, newEx, 'Name:
Type:');
parent.focusTextBox('stfilename');
}
function newFolderEx() {
@@ -901,7 +934,7 @@ function redrawScriptTree() {
var el = scriptEl[0];
folder_id = el.getAttribute('x-data-folder');
}
- parent.setDialogMode(2, "New Folder", 3, newFolderEx, '');
+ parent.setDialogMode(2, "New Folder", 3, newFolderEx, '');
parent.focusTextBox('stfoldername');
}
function goScript(el) {
@@ -928,7 +961,7 @@ function redrawScriptTree() {
var el = els[0];
var name = el.innerHTML;
var id = el.getAttribute('x-data-id');
- parent.setDialogMode(2, "Delete " + name, 3, deleteEx, 'Are you sure? ');
+ parent.setDialogMode(2, "Delete " + name, 3, deleteEx, 'Are you sure? ');
}
function deleteScheduleEx() {
var id = parent.document.getElementById('stdelid').value;
@@ -936,7 +969,7 @@ function redrawScriptTree() {
}
function deleteSchedule(el) {
var id = el.parentNode.parentNode.getAttribute('x-data-id');
- parent.setDialogMode(2, "Delete Schedule", 3, deleteScheduleEx, 'Are you sure you want to delete this schedule? ');
+ parent.setDialogMode(2, "Delete Schedule", 3, deleteScheduleEx, 'Are you sure you want to delete this schedule? ');
}
function toggleCollapse(el) {
var xdf = el.getAttribute('x-data-path');
@@ -945,12 +978,12 @@ function redrawScriptTree() {
folderEls.forEach(function(e){
if (e === el) return;
if (e.getAttribute('x-data-path').indexOf(xdf) !== -1) {
- if (e.style.display == 'none') {
+ if (e.style.display == 'none') {
if (showHide === null) showHide = '';
} else {
if (showHide === null) showHide = 'none';
}
- e.style.display = showHide;
+ e.style.display = showHide;
}
});
goScript(el);
@@ -966,7 +999,7 @@ function redrawScriptTree() {
if (dragTimer != null) dragTimer = null;
//document.getElementById('list').innerHTML = '';
}
-
+
function fileUpload(files) {
if (files == null) files = document.getElementById('files').files;
var path = null;
@@ -997,7 +1030,7 @@ function redrawScriptTree() {
dragTimer = setTimeout(function(){ dragCounter = 0; QV('dropBlock', false); }, 100);
}
}
-
+
function dropMove(evt) {
const move_id = evt.dataTransfer.getData('text');
const container_id = evt.target.parentNode.getAttribute('x-data-id');
@@ -1017,6 +1050,6 @@ function redrawScriptTree() {
}
});
dropZone.addEventListener('drop', handleFileSelect);
-
+