From 65cd823dacddb5bd16e7f625fec44dd113ada921 Mon Sep 17 00:00:00 2001 From: Cory Funk Date: Thu, 2 Jul 2026 14:20:23 -0500 Subject: [PATCH 1/8] Update user.handlebars --- views/user.handlebars | 1986 ++++++++++++++++++++--------------------- 1 file changed, 964 insertions(+), 1022 deletions(-) diff --git a/views/user.handlebars b/views/user.handlebars index f69a731..e4a262a 100644 --- a/views/user.handlebars +++ b/views/user.handlebars @@ -1,1022 +1,964 @@ - - - - - - -
- - Upload: -
-
- New - Rename - Edit - Delete - New Folder - Download - Run -
-
-
-
-
-
-
Advanced Run
-
-
-
- - -
-
-
- - -
Meshes
-
-
- - -
Tags
-
-
-
Node Schedules
-
- - -
ScriptAuthorEveryStartingEndingLast RunNext RunAction
-
-
Script Schedules
-
- - -
NodeAuthorEveryStartingEndingLast RunNext RunAction
-
-
Node History
-
- - -
TimeRun ByScriptStatusReturn Value
-
-
Script History
-
- - -
TimeRun ByNodeStatusReturn Value
-
-
Variables
-
- - -
Variable NameValueScopeScope TargetAction
-
- [+] -
-
- -
-
-
- - - + + + + + + +
+ + Upload: +
+
+ New + Rename + Edit + Delete + New Folder + Download + Run +
+
+
+
+
+
+
Advanced Run
+
+
+
+ + +
+
+
+ + +
Meshes
+
+
+ + +
Tags
+
+
+
Node Schedules
+
+ + +
ScriptAuthorEveryStartingEndingLast RunNext RunAction
+
+
Script Schedules
+
+ + +
NodeAuthorEveryStartingEndingLast RunNext RunAction
+
+
Node History
+
+ + +
TimeRun ByScriptStatusReturn Value
+
+
Script History
+
+ + +
TimeRun ByNodeStatusReturn Value
+
+
Variables
+
+ + +
Variable NameValueScopeScope TargetAction
+
+ [+] +
+
+ +
+
+
+ + + From 01814004bf7cb63ad6dd34c2e675624f12a74b2c Mon Sep 17 00:00:00 2001 From: Cory Funk Date: Thu, 2 Jul 2026 14:28:10 -0500 Subject: [PATCH 2/8] Create .DS_Store --- .DS_Store | Bin 0 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Thu, 2 Jul 2026 14:35:22 -0500 Subject: [PATCH 3/8] Update version and author in config.json --- config.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config.json b/config.json index 00cd76a..7823426 100644 --- a/config.json +++ b/config.json @@ -1,18 +1,18 @@ { "name": "ScriptTask", "shortName": "scripttask", - "version": "0.0.20", - "author": "Ryan Blenis", + "version": "0.0.21", + "author": "Ryan Blenis / Cory Funk", "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", + "homepage": "https://github.com/fud18/MeshCentral-ScriptTask", + "changelogUrl": "https://raw.githubusercontent.com/fud18/MeshCentral-ScriptTask/master/changelog.md", + "configUrl": "https://raw.githubusercontent.com/fud18/MeshCentral-ScriptTask/master/config.json", + "downloadUrl": "https://github.com/fud18/MeshCentral-ScriptTask/archive/refs/heads/master.zip", "repository": { "type": "git", - "url": "https://github.com/ryanblenis/MeshCentral-ScriptTask.git" + "url": "https://github.com/fud18/MeshCentral-ScriptTask.git" }, - "versionHistoryUrl": "https://api.github.com/repos/ryanblenis/MeshCentral-ScriptTask/tags", + "versionHistoryUrl": "https://api.github.com/repos/fud18/MeshCentral-ScriptTask/tags", "meshCentralCompat": ">=1.1.35" -} \ No newline at end of file +} From fe43f72c7f79d547493e3c0347c02fb431c94ff1 Mon Sep 17 00:00:00 2001 From: Cory Funk Date: Thu, 2 Jul 2026 15:30:43 -0500 Subject: [PATCH 4/8] Update user.handlebars --- views/user.handlebars | 218 ++++++++++++++++++++++++++++++++---------- 1 file changed, 168 insertions(+), 50 deletions(-) diff --git a/views/user.handlebars b/views/user.handlebars index e4a262a..86b90df 100644 --- a/views/user.handlebars +++ b/views/user.handlebars @@ -56,19 +56,42 @@ background-color: lightgray; } #controlBar { + display: flex; + flex-wrap: wrap; + gap: 6px; + align-items: center; width: 100%; - height: 20px; - border-bottom: 1px solid black; - font-size: smaller; + min-height: 30px; + border-bottom: 1px solid #d7d7d7; + padding: 0 0 7px 0; margin-bottom: 7px; + font-size: 12px; } - #controlBar span { + .stButton { + display: inline-block; + border: 1px solid #b7b7b7; + border-radius: 3px; + background: linear-gradient(#ffffff, #e9e9e9); + color: #222; cursor: pointer; - padding-left: 4px; - padding-right: 4px; + font-family: inherit; + font-size: 12px; + line-height: 22px; + min-height: 24px; + padding: 0 10px; + text-decoration: none; + user-select: none; + white-space: nowrap; + } + .stButton:hover { + background: linear-gradient(#f7f7f7, #dddddd); + border-color: #999; } - #controlBar > span:nth-child(n+2) { - border-left: 1px solid black; + .stButton:active { + background: linear-gradient(#dddddd, #f7f7f7); + } + .stButtonDanger { + color: #7f1d1d; } .infoBar { background-color: #777; @@ -172,6 +195,11 @@ .flink { cursor: pointer; } + .stActionLink { + color: #0366d6; + cursor: pointer; + text-decoration: underline; + }
@@ -179,13 +207,13 @@ Upload:
- New - Rename - Edit - Delete - New Folder - Download - Run + + + + + + +
@@ -194,10 +222,10 @@
Advanced Run
-
+
- +
@@ -241,7 +269,7 @@ Variable NameValueScopeScope TargetAction
- [+] + [+]
@@ -291,7 +319,7 @@ function updateNodesTable() { var item = {...parent.meshes[i], ...{}}; if (item.mtype == 2) { let tpl = ` - + `; nodeRowIns.insertAdjacentHTML('beforeend', tpl); } @@ -299,7 +327,7 @@ function updateNodesTable() { var nodeRowIns = document.querySelector('#mRunTblTag'); tagList.forEach(function(i) { let tpl = ` - + `; nodeRowIns.insertAdjacentHTML('beforeend', tpl); }); @@ -335,9 +363,8 @@ function selAllNodes(el) { return true; } - -function bindScriptTaskUi() { - var controlActions = { +function bindScriptTaskButtons() { + var actions = { new: goNew, rename: goRename, edit: goEdit, @@ -345,37 +372,125 @@ function bindScriptTaskUi() { newFolder: goNewFolder, download: goDownload, run: goRun, - advancedRun: goAdvancedRun, - newVar: newVar + advancedRun: goAdvancedRun }; - document.addEventListener('click', function(ev) { - var actionEl = ev.target.closest('[data-st-action]'); - if (actionEl) { - var action = actionEl.getAttribute('data-st-action'); - if (controlActions[action]) { ev.preventDefault(); controlActions[action](); return false; } - if (action == 'selectAllNodes') { return selAllNodes(actionEl); } - if (action == 'selectNodesByMesh') { return selNodesByMesh(actionEl); } - if (action == 'selectNodesByTag') { return selNodesByTag(actionEl); } - } + document.querySelectorAll('[data-st-action]').forEach(function(btn) { + if (btn.getAttribute('data-st-bound') == '1') return; + btn.setAttribute('data-st-bound', '1'); + btn.addEventListener('click', function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + var action = btn.getAttribute('data-st-action'); + if (actions[action]) actions[action](); + }); + }); +} - var scriptEl = ev.target.closest('.liscript'); - if (scriptEl) { ev.preventDefault(); goScript(scriptEl); return false; } +function doOnLoad() { + bindScriptTaskButtons(); + redrawScriptTree(); + 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 }); +} + +function selectPreviouslySelectedScript() { + var sel_item = parent.getstore('_scripttask_sel_item', null) + if (sel_item != null) { + var s = document.getElementById(sel_item); + if (s != null) { + s.classList.toggle('liselected'); + goScript(s); + } + } + if (sel_item != null) parent.meshserver.send({ 'action': 'plugin', 'plugin': 'scripttask', 'pluginaction': 'loadScriptHistory', 'scriptId': sel_item }); +} - var folderEl = ev.target.closest('.lifolder'); - if (folderEl) { ev.preventDefault(); toggleCollapse(folderEl); return false; } +function goRun() { + var selScript = document.querySelectorAll('.liselected'); + if (selScript.length) { + var scriptId = selScript[0].getAttribute('x-data-id'); + if (scriptId == selScript[0].getAttribute('x-data-folder')) + { + 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.'); + } +} - var delSched = ev.target.closest('.delSched'); - if (delSched) { ev.preventDefault(); deleteSchedule(delSched); return false; } +function goEdit() { + var selScript = document.querySelectorAll('.liselected'); + if (selScript.length && (selScript[0].getAttribute('x-data-id') != selScript[0].getAttribute('x-data-folder'))) { + var scriptId = selScript[0].getAttribute('x-data-id'); + window.open('/pluginadmin.ashx?pin=scripttask&user=1&edit=1&id=' + scriptId, '_blank'); + window.callback = function(sd) { + 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.'); + } +} - var editVarEl = ev.target.closest('.st-edit-var'); - if (editVarEl) { ev.preventDefault(); editVar(editVarEl); return false; } +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) { + var scriptId = selScript[0].getAttribute('x-data-id'); + if (scriptId == selScript[0].getAttribute('x-data-folder')) { + parent.setDialogMode(2, "Oops!", 1, null, 'Please select a script. A folder is currently selected.'); + return; + } + 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.'); + } +} - var delVarEl = ev.target.closest('.st-del-var'); - if (delVarEl) { ev.preventDefault(); delVar(delVarEl); return false; } +var coll = document.getElementsByClassName("infoBar"); +for (var i = 0; i < coll.length; i++) { + coll[i].addEventListener("click", function() { + this.classList.toggle("active"); + var content = this.nextElementSibling; + if (content.style.display === "block") { + content.style.display = "none"; + } else { + content.style.display = "block"; + } + content.style.maxHeight = '300px'; + content.style.overflowY = 'scroll'; + resizeIframe(); }); +} - function goDownload() { +function goDownload() { var isSelected = document.querySelectorAll('.liselected'); if (isSelected.length == 0) return; var sel = isSelected[0]; @@ -405,12 +520,12 @@ function redrawScriptTree() { indent = (f.path.match(/\//g) || []).length + 1; var name = f.path.match(/[^\/]+$/); folder_id = f._id; - str += '
' + name + '
'; + str += '
' + name + '
'; lastpath = f.path; indent += 1; } if (f.type != 'folder') { - str += '
' + f.name + ' [' + f.filetype + ']
'; + str += '
' + f.name + ' [' + f.filetype + ']
'; } }); @@ -584,7 +699,7 @@ function redrawScriptTree() { if (vd.scope == 'script' && vd.scopeTarget != scopeTargetScriptId) return; if (vd.scope == 'mesh' && vd.scopeTarget != parent.currentNode.meshid) return; if (vd.scope == 'node' && vd.scopeTarget != parent.currentNode._id) return; - let actionHtml = 'Edit Delete'; + let actionHtml = 'Edit Delete'; let tpl = '' + vd.name + ' \ ' + vd.value + ' \ ' + vd.scopeTxt + ' \ @@ -716,7 +831,7 @@ function redrawScriptTree() { if (nh.nextRun == null) nh.nextRunTxt = 'Never'; if (nh.nextRun < nh.lastRun) nh.nextRunTxt = 'Running now'; - nh.actionTxt = 'Delete'; + nh.actionTxt = ''; return nh; } function secondsToHms(d) { @@ -877,7 +992,10 @@ function redrawScriptTree() { parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id }); } function deleteSchedule(el) { - var id = el.parentNode.parentNode.getAttribute('x-data-id'); + var row = el.closest ? el.closest('tr') : el.parentNode.parentNode; + if (!row) return; + var id = row.getAttribute('x-data-id'); + if (!id) return; parent.setDialogMode(2, "Delete Schedule", 3, deleteScheduleEx, 'Are you sure you want to delete this schedule? '); } function toggleCollapse(el) { From 0b01ecbd5ac6556bdf741f20c99b9573da6f3cf4 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 2 Jul 2026 16:54:51 -0500 Subject: [PATCH 5/8] Fix ScriptTask button handlers and schedule actions --- views/user.handlebars | 73 ++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/views/user.handlebars b/views/user.handlebars index 86b90df..9ea02b6 100644 --- a/views/user.handlebars +++ b/views/user.handlebars @@ -207,13 +207,13 @@ Upload:
- - - - - - - + + + + + + +
@@ -222,7 +222,7 @@
Advanced Run
-
+
@@ -925,10 +925,11 @@ function redrawScriptTree() { var scriptEl = document.querySelectorAll('.liselected'); if (scriptEl.length != 1) return; var el = scriptEl[0]; - var name = el.querySelector('.fname').innerHTML; + var oldName = el.querySelector('.fname').innerHTML; var id = el.getAttribute('x-data-id'); - parent.setDialogMode(2, "Rename " + name, 3, renameEx, ''); - parent.focusTextBox('stfilename'); + var name = prompt('Rename:', oldName); + if (!name) return; + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'rename', name: name, id: id, currentNodeId: parent.currentNode._id }); } function newEx() { var name = parent.document.getElementById('stfilename').value; @@ -940,12 +941,27 @@ function redrawScriptTree() { var scriptEl = document.querySelectorAll('.liselected'); var folder_id = null; if (scriptEl.length > 0) { - var el = scriptEl[0]; - folder_id = el.getAttribute('x-data-folder'); + folder_id = scriptEl[0].getAttribute('x-data-folder'); } - parent.setDialogMode(2, "New Script", 3, newEx, 'Name:
Type:'); - parent.focusTextBox('stfilename'); + if (folder_id == 'null') folder_id = null; + + var name = prompt('New script name:', 'NewScript.ps1'); + if (!name) return; + + var ext = name.split('.').pop().toLowerCase(); + var fileType = (ext == 'ps1' || ext == 'bat') ? ext : 'bash'; + + parent.meshserver.send({ + action: 'plugin', + plugin: 'scripttask', + pluginaction: 'new', + name: name, + parent_id: folder_id, + filetype: fileType, + currentNodeId: parent.currentNode._id + }); } + function newFolderEx() { var name = parent.document.getElementById('stfoldername').value; var parent_id = parent.document.getElementById('stfolderid').value; @@ -954,12 +970,11 @@ function redrawScriptTree() { function goNewFolder() { var scriptEl = document.querySelectorAll('.liselected'); var folder_id = null; - if (scriptEl.length > 0) { - var el = scriptEl[0]; - folder_id = el.getAttribute('x-data-folder'); - } - parent.setDialogMode(2, "New Folder", 3, newFolderEx, ''); - parent.focusTextBox('stfoldername'); + if (scriptEl.length > 0) folder_id = scriptEl[0].getAttribute('x-data-folder'); + if (folder_id == 'null') folder_id = null; + var name = prompt('New folder name:', 'New Folder'); + if (!name) return; + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'newFolder', name: name, parent_id: folder_id, currentNodeId: parent.currentNode._id }); } function goScript(el) { var xdi = el.getAttribute('x-data-id'); @@ -983,20 +998,22 @@ function redrawScriptTree() { var els = document.querySelectorAll('.liselected'); if (els.length == 0) return; 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? '); + var name = el.querySelector('.fname') ? el.querySelector('.fname').innerHTML : el.innerHTML; + if (!confirm('Delete ' + name + '?')) return; + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id, currentNodeId: parent.currentNode._id }); } function deleteScheduleEx() { var id = parent.document.getElementById('stdelid').value; parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id }); } function deleteSchedule(el) { - var row = el.closest ? el.closest('tr') : el.parentNode.parentNode; - if (!row) return; - var id = row.getAttribute('x-data-id'); - if (!id) return; - parent.setDialogMode(2, "Delete Schedule", 3, deleteScheduleEx, 'Are you sure you want to delete this schedule? '); + var row = el.closest ? el.closest('tr') : el.parentNode.parentNode; + if (!row) return; + var id = row.getAttribute('x-data-id'); + if (!id) return; + if (!confirm('Delete this scheduled job?')) return; + parent.meshserver.send({ action: 'plugin', plugin: 'scripttask', pluginaction: 'delete', id: id, currentNodeId: parent.currentNode._id }); } function toggleCollapse(el) { var xdf = el.getAttribute('x-data-path'); From 60e7f471d8ee73745f721a91f52481cc45690e14 Mon Sep 17 00:00:00 2001 From: fud18 Date: Thu, 2 Jul 2026 18:13:41 -0500 Subject: [PATCH 6/8] Delete .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Mon, 6 Jul 2026 16:56:30 -0500 Subject: [PATCH 7/8] Fix ScriptTask UI actions and script editor save --- scripttask.js | 6 ++++++ views/scriptedit.handlebars | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/scripttask.js b/scripttask.js index b6f9eec..6bffbd1 100644 --- a/scripttask.js +++ b/scripttask.js @@ -69,6 +69,12 @@ module.exports.scripttask = function (parent) { obj.db.get(job.scriptId) .then(async (script) => { script = script[0]; + + if (!script || typeof script.content !== 'string') { + console.log('PLUGIN: ScriptTask: Skipping job with missing script content. scriptId=' + job.scriptId + ', node=' + job.node); + return; + } + var foundVars = script.content.match(/#(.*?)#/g); var replaceVars = {}; if (foundVars != null && foundVars.length > 0) { diff --git a/views/scriptedit.handlebars b/views/scriptedit.handlebars index 8111f4f..16ef23c 100644 --- a/views/scriptedit.handlebars +++ b/views/scriptedit.handlebars @@ -37,8 +37,8 @@
Script Name:
- - + +
@@ -57,8 +57,17 @@ function doOnLoad() { function goSave() { scriptData.content = Q('scriptContent').value; scriptData.name = Q('scriptName').value; - window.opener.callback(scriptData); - //goClose(); + + try { + if (window.opener && typeof window.opener.callback === 'function') { + window.opener.callback(scriptData); + } else { + alert('Unable to save script: parent callback was not found.'); + return; + } + } finally { + window.close(); + } } function goClose() { From e7cfa47c30f79555bba8b674ab3d06ada60044f1 Mon Sep 17 00:00:00 2001 From: fud18 Date: Tue, 7 Jul 2026 07:34:19 -0500 Subject: [PATCH 8/8] Update author field in config.json --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 7823426..2eab887 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "name": "ScriptTask", "shortName": "scripttask", "version": "0.0.21", - "author": "Ryan Blenis / Cory Funk", + "author": "Ryan Blenis", "description": "Script (PowerShell, BAT, Bash) runner for endpoints", "hasAdminPanel": false, "homepage": "https://github.com/fud18/MeshCentral-ScriptTask",