Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5603a5233 | ||
|
|
73890f553c | ||
|
|
f6243b8968 | ||
|
|
3770dc74d4 | ||
|
|
45f4e947c5 | ||
|
|
9928d7c6e1 | ||
|
|
ae7c0e9195 | ||
|
|
e90b640602 | ||
|
|
ba7529d3f5 | ||
|
|
34667f252e | ||
|
|
d18bddcb7b | ||
|
|
96dff49d33 | ||
|
|
b389728338 | ||
|
|
cdc7da86f3 | ||
|
|
4745cc0378 | ||
|
|
434f132479 | ||
|
|
fb0f31ffc7 | ||
|
|
bb1d73c0ae | ||
|
|
0e823d1191 | ||
|
|
48f4199ff3 | ||
|
|
eaf379587b | ||
|
|
672446b7d1 | ||
|
|
dfe52c1b07 | ||
|
|
d63df03ad8 | ||
|
|
aba4f9f2ce | ||
|
|
ac5c1e7803 | ||
|
|
d521dbf50e | ||
|
|
f210ed3e6a | ||
|
|
df3cac4ea6 | ||
|
|
f778c5175b | ||
|
|
6c66ff28dd | ||
|
|
d5b6ec702b | ||
|
|
c62a5fcef2 | ||
|
|
59c47e9200 | ||
|
|
4ba44d8932 | ||
|
|
27dae05e1b | ||
|
|
a251ae9b90 | ||
|
|
7e960b2bde | ||
|
|
5df4825158 | ||
|
|
8984d06d93 | ||
|
|
eed7aac047 | ||
|
|
54b068de4a | ||
|
|
f0f33b00b6 | ||
|
|
1043405088 | ||
|
|
0131b10805 | ||
|
|
a19b441f62 | ||
|
|
28edc31d43 | ||
|
|
0f9872a818 | ||
|
|
76ce4296f3 | ||
|
|
3dd2671380 | ||
|
|
298ca31332 | ||
|
|
8f911aa6b9 | ||
|
|
82a5c7d9b1 | ||
|
|
7f013dcdba | ||
|
|
68e2e16076 | ||
|
|
ea23c763c9 | ||
|
|
5dcecb3206 | ||
|
|
5bd48e2d0e | ||
|
|
afd0a02589 | ||
|
|
2379192d53 | ||
|
|
a6489290c8 | ||
|
|
5f74c43415 | ||
|
|
aa8b84a302 | ||
|
|
b987d041b0 | ||
|
|
b62e37307e | ||
|
|
61a59aa6ac | ||
|
|
f79ec27f1d | ||
|
|
b993fe380f | ||
|
|
d974b5f55f | ||
|
|
1be6f8f87a |
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2 on 2021-04-11 01:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0013_user_client_tree_sort'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='client_tree_splitter',
|
||||
field=models.PositiveIntegerField(default=11),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2 on 2021-04-11 03:03
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0014_user_client_tree_splitter'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='loading_bar_color',
|
||||
field=models.CharField(default='red', max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -36,6 +36,8 @@ class User(AbstractUser, BaseAuditModel):
|
||||
client_tree_sort = models.CharField(
|
||||
max_length=50, choices=CLIENT_TREE_SORT_CHOICES, default="alphafail"
|
||||
)
|
||||
client_tree_splitter = models.PositiveIntegerField(default=11)
|
||||
loading_bar_color = models.CharField(max_length=255, default="red")
|
||||
|
||||
agent = models.OneToOneField(
|
||||
"agents.Agent",
|
||||
|
||||
@@ -13,6 +13,8 @@ class UserUISerializer(ModelSerializer):
|
||||
"agent_dblclick_action",
|
||||
"default_agent_tbl_tab",
|
||||
"client_tree_sort",
|
||||
"client_tree_splitter",
|
||||
"loading_bar_color",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -278,6 +278,8 @@ class TestUserAction(TacticalTestCase):
|
||||
"agent_dblclick_action": "editagent",
|
||||
"default_agent_tbl_tab": "mixed",
|
||||
"client_tree_sort": "alpha",
|
||||
"client_tree_splitter": 14,
|
||||
"loading_bar_color": "green",
|
||||
}
|
||||
r = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
@@ -195,6 +195,27 @@ class Agent(BaseAuditModel):
|
||||
except:
|
||||
return ["unknown cpu model"]
|
||||
|
||||
@property
|
||||
def graphics(self):
|
||||
ret, mrda = [], []
|
||||
try:
|
||||
graphics = self.wmi_detail["graphics"]
|
||||
for i in graphics:
|
||||
caption = [x["Caption"] for x in i if "Caption" in x][0]
|
||||
if "microsoft remote display adapter" in caption.lower():
|
||||
mrda.append("yes")
|
||||
continue
|
||||
|
||||
ret.append([x["Caption"] for x in i if "Caption" in x][0])
|
||||
|
||||
# only return this if no other graphics cards
|
||||
if not ret and mrda:
|
||||
return "Microsoft Remote Display Adapter"
|
||||
|
||||
return ", ".join(ret)
|
||||
except:
|
||||
return "Graphics info requires agent v1.4.14"
|
||||
|
||||
@property
|
||||
def local_ips(self):
|
||||
ret = []
|
||||
@@ -322,7 +343,7 @@ class Agent(BaseAuditModel):
|
||||
online = [
|
||||
agent
|
||||
for agent in Agent.objects.only(
|
||||
"pk", "last_seen", "overdue_time", "offline_time"
|
||||
"pk", "agent_id", "last_seen", "overdue_time", "offline_time"
|
||||
)
|
||||
if agent.status == "online"
|
||||
]
|
||||
@@ -819,12 +840,6 @@ class RecoveryAction(models.Model):
|
||||
def __str__(self):
|
||||
return f"{self.agent.hostname} - {self.mode}"
|
||||
|
||||
def send(self):
|
||||
ret = {"recovery": self.mode}
|
||||
if self.mode == "command":
|
||||
ret["cmd"] = self.command
|
||||
return ret
|
||||
|
||||
|
||||
class Note(models.Model):
|
||||
agent = models.ForeignKey(
|
||||
|
||||
@@ -16,6 +16,7 @@ class AgentSerializer(serializers.ModelSerializer):
|
||||
local_ips = serializers.ReadOnlyField()
|
||||
make_model = serializers.ReadOnlyField()
|
||||
physical_disks = serializers.ReadOnlyField()
|
||||
graphics = serializers.ReadOnlyField()
|
||||
checks = serializers.ReadOnlyField()
|
||||
timezone = serializers.ReadOnlyField()
|
||||
all_timezones = serializers.SerializerMethodField()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import asyncio
|
||||
import datetime as dt
|
||||
import json
|
||||
import random
|
||||
import subprocess
|
||||
import tempfile
|
||||
import requests
|
||||
import urllib.parse
|
||||
from time import sleep
|
||||
from typing import Union
|
||||
|
||||
@@ -13,21 +12,33 @@ from loguru import logger
|
||||
from packaging import version as pyver
|
||||
|
||||
from agents.models import Agent
|
||||
from core.models import CoreSettings
|
||||
from core.models import CoreSettings, CodeSignToken
|
||||
from logs.models import PendingAction
|
||||
from scripts.models import Script
|
||||
from tacticalrmm.celery import app
|
||||
from tacticalrmm.utils import run_nats_api_cmd
|
||||
|
||||
logger.configure(**settings.LOG_CONFIG)
|
||||
|
||||
|
||||
def agent_update(pk: int) -> str:
|
||||
def _get_exegen_url() -> str:
|
||||
urls: list[str] = settings.EXE_GEN_URLS
|
||||
for url in urls:
|
||||
try:
|
||||
r = requests.get(url, timeout=10)
|
||||
except:
|
||||
continue
|
||||
|
||||
if r.status_code == 200:
|
||||
return url
|
||||
|
||||
return random.choice(urls)
|
||||
|
||||
|
||||
def agent_update(pk: int, codesigntoken: str = None) -> str:
|
||||
agent = Agent.objects.get(pk=pk)
|
||||
|
||||
if pyver.parse(agent.version) <= pyver.parse("1.1.11"):
|
||||
logger.warning(
|
||||
f"{agent.hostname} v{agent.version} is running an unsupported version. Refusing to auto update."
|
||||
)
|
||||
if pyver.parse(agent.version) <= pyver.parse("1.3.0"):
|
||||
return "not supported"
|
||||
|
||||
# skip if we can't determine the arch
|
||||
@@ -37,18 +48,15 @@ def agent_update(pk: int) -> str:
|
||||
)
|
||||
return "noarch"
|
||||
|
||||
# removed sqlite in 1.4.0 to get rid of cgo dependency
|
||||
# 1.3.0 has migration func to move from sqlite to win registry, so force an upgrade to 1.3.0 if old agent
|
||||
if pyver.parse(agent.version) >= pyver.parse("1.3.0"):
|
||||
version = settings.LATEST_AGENT_VER
|
||||
url = agent.winagent_dl
|
||||
inno = agent.win_inno_exe
|
||||
version = settings.LATEST_AGENT_VER
|
||||
inno = agent.win_inno_exe
|
||||
|
||||
if codesigntoken is not None and pyver.parse(version) >= pyver.parse("1.5.0"):
|
||||
base_url = _get_exegen_url() + "/api/v1/winagents/?"
|
||||
params = {"version": version, "arch": agent.arch, "token": codesigntoken}
|
||||
url = base_url + urllib.parse.urlencode(params)
|
||||
else:
|
||||
version = "1.3.0"
|
||||
inno = (
|
||||
"winagent-v1.3.0.exe" if agent.arch == "64" else "winagent-v1.3.0-x86.exe"
|
||||
)
|
||||
url = f"https://github.com/wh1te909/rmmagent/releases/download/v1.3.0/{inno}"
|
||||
url = agent.winagent_dl
|
||||
|
||||
if agent.pendingactions.filter(
|
||||
action_type="agentupdate", status="pending"
|
||||
@@ -81,10 +89,15 @@ def agent_update(pk: int) -> str:
|
||||
|
||||
@app.task
|
||||
def send_agent_update_task(pks: list[int]) -> None:
|
||||
try:
|
||||
codesigntoken = CodeSignToken.objects.first().token
|
||||
except:
|
||||
codesigntoken = None
|
||||
|
||||
chunks = (pks[i : i + 30] for i in range(0, len(pks), 30))
|
||||
for chunk in chunks:
|
||||
for pk in chunk:
|
||||
agent_update(pk)
|
||||
agent_update(pk, codesigntoken)
|
||||
sleep(0.05)
|
||||
sleep(4)
|
||||
|
||||
@@ -95,6 +108,11 @@ def auto_self_agent_update_task() -> None:
|
||||
if not core.agent_auto_update:
|
||||
return
|
||||
|
||||
try:
|
||||
codesigntoken = CodeSignToken.objects.first().token
|
||||
except:
|
||||
codesigntoken = None
|
||||
|
||||
q = Agent.objects.only("pk", "version")
|
||||
pks: list[int] = [
|
||||
i.pk
|
||||
@@ -105,7 +123,7 @@ def auto_self_agent_update_task() -> None:
|
||||
chunks = (pks[i : i + 30] for i in range(0, len(pks), 30))
|
||||
for chunk in chunks:
|
||||
for pk in chunk:
|
||||
agent_update(pk)
|
||||
agent_update(pk, codesigntoken)
|
||||
sleep(0.05)
|
||||
sleep(4)
|
||||
|
||||
@@ -257,30 +275,13 @@ def run_script_email_results_task(
|
||||
logger.error(e)
|
||||
|
||||
|
||||
def _get_nats_config() -> dict:
|
||||
return {
|
||||
"key": settings.SECRET_KEY,
|
||||
"natsurl": f"tls://{settings.ALLOWED_HOSTS[0]}:4222",
|
||||
}
|
||||
|
||||
|
||||
@app.task
|
||||
def monitor_agents_task() -> None:
|
||||
agents = Agent.objects.only(
|
||||
"pk", "agent_id", "last_seen", "overdue_time", "offline_time"
|
||||
)
|
||||
ret = [i.agent_id for i in agents if i.status != "online"]
|
||||
config = _get_nats_config()
|
||||
config["agents"] = ret
|
||||
with tempfile.NamedTemporaryFile() as fp:
|
||||
with open(fp.name, "w") as f:
|
||||
json.dump(config, f)
|
||||
|
||||
cmd = ["/usr/local/bin/nats-api", "-c", fp.name, "-m", "monitor"]
|
||||
try:
|
||||
subprocess.run(cmd, capture_output=True, timeout=30)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
ids = [i.agent_id for i in agents if i.status != "online"]
|
||||
run_nats_api_cmd("monitor", ids)
|
||||
|
||||
|
||||
@app.task
|
||||
@@ -288,15 +289,5 @@ def get_wmi_task() -> None:
|
||||
agents = Agent.objects.only(
|
||||
"pk", "agent_id", "last_seen", "overdue_time", "offline_time"
|
||||
)
|
||||
ret = [i.agent_id for i in agents if i.status == "online"]
|
||||
config = _get_nats_config()
|
||||
config["agents"] = ret
|
||||
with tempfile.NamedTemporaryFile() as fp:
|
||||
with open(fp.name, "w") as f:
|
||||
json.dump(config, f)
|
||||
|
||||
cmd = ["/usr/local/bin/nats-api", "-c", fp.name, "-m", "wmi"]
|
||||
try:
|
||||
subprocess.run(cmd, capture_output=True, timeout=30)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
ids = [i.agent_id for i in agents if i.status == "online"]
|
||||
run_nats_api_cmd("wmi", ids)
|
||||
|
||||
@@ -914,8 +914,9 @@ class TestAgentTasks(TacticalTestCase):
|
||||
self.authenticate()
|
||||
self.setup_coresettings()
|
||||
|
||||
@patch("agents.tasks._get_exegen_url")
|
||||
@patch("agents.models.Agent.nats_cmd")
|
||||
def test_agent_update(self, nats_cmd):
|
||||
def test_agent_update(self, nats_cmd, get_exe):
|
||||
from agents.tasks import agent_update
|
||||
|
||||
agent_noarch = baker.make_recipe(
|
||||
@@ -926,63 +927,96 @@ class TestAgentTasks(TacticalTestCase):
|
||||
r = agent_update(agent_noarch.pk)
|
||||
self.assertEqual(r, "noarch")
|
||||
|
||||
agent_1111 = baker.make_recipe(
|
||||
"agents.agent",
|
||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||
version="1.1.11",
|
||||
)
|
||||
r = agent_update(agent_1111.pk)
|
||||
self.assertEqual(r, "not supported")
|
||||
|
||||
agent64_1112 = baker.make_recipe(
|
||||
"agents.agent",
|
||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||
version="1.1.12",
|
||||
)
|
||||
|
||||
r = agent_update(agent64_1112.pk)
|
||||
self.assertEqual(r, "created")
|
||||
action = PendingAction.objects.get(agent__pk=agent64_1112.pk)
|
||||
self.assertEqual(action.action_type, "agentupdate")
|
||||
self.assertEqual(action.status, "pending")
|
||||
self.assertEqual(
|
||||
action.details["url"],
|
||||
"https://github.com/wh1te909/rmmagent/releases/download/v1.3.0/winagent-v1.3.0.exe",
|
||||
)
|
||||
self.assertEqual(action.details["inno"], "winagent-v1.3.0.exe")
|
||||
self.assertEqual(action.details["version"], "1.3.0")
|
||||
nats_cmd.assert_called_with(
|
||||
{
|
||||
"func": "agentupdate",
|
||||
"payload": {
|
||||
"url": "https://github.com/wh1te909/rmmagent/releases/download/v1.3.0/winagent-v1.3.0.exe",
|
||||
"version": "1.3.0",
|
||||
"inno": "winagent-v1.3.0.exe",
|
||||
},
|
||||
},
|
||||
wait=False,
|
||||
)
|
||||
|
||||
agent_64_130 = baker.make_recipe(
|
||||
agent_130 = baker.make_recipe(
|
||||
"agents.agent",
|
||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||
version="1.3.0",
|
||||
)
|
||||
nats_cmd.return_value = "ok"
|
||||
r = agent_update(agent_64_130.pk)
|
||||
r = agent_update(agent_130.pk)
|
||||
self.assertEqual(r, "not supported")
|
||||
|
||||
# test __without__ code signing
|
||||
agent64_nosign = baker.make_recipe(
|
||||
"agents.agent",
|
||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||
version="1.4.14",
|
||||
)
|
||||
|
||||
r = agent_update(agent64_nosign.pk, None)
|
||||
self.assertEqual(r, "created")
|
||||
action = PendingAction.objects.get(agent__pk=agent64_nosign.pk)
|
||||
self.assertEqual(action.action_type, "agentupdate")
|
||||
self.assertEqual(action.status, "pending")
|
||||
self.assertEqual(
|
||||
action.details["url"],
|
||||
f"https://github.com/wh1te909/rmmagent/releases/download/v{settings.LATEST_AGENT_VER}/winagent-v{settings.LATEST_AGENT_VER}.exe",
|
||||
)
|
||||
self.assertEqual(
|
||||
action.details["inno"], f"winagent-v{settings.LATEST_AGENT_VER}.exe"
|
||||
)
|
||||
self.assertEqual(action.details["version"], settings.LATEST_AGENT_VER)
|
||||
nats_cmd.assert_called_with(
|
||||
{
|
||||
"func": "agentupdate",
|
||||
"payload": {
|
||||
"url": settings.DL_64,
|
||||
"url": f"https://github.com/wh1te909/rmmagent/releases/download/v{settings.LATEST_AGENT_VER}/winagent-v{settings.LATEST_AGENT_VER}.exe",
|
||||
"version": settings.LATEST_AGENT_VER,
|
||||
"inno": f"winagent-v{settings.LATEST_AGENT_VER}.exe",
|
||||
},
|
||||
},
|
||||
wait=False,
|
||||
)
|
||||
action = PendingAction.objects.get(agent__pk=agent_64_130.pk)
|
||||
|
||||
# test __with__ code signing (64 bit)
|
||||
codesign = baker.make("core.CodeSignToken", token="testtoken123")
|
||||
agent64_sign = baker.make_recipe(
|
||||
"agents.agent",
|
||||
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
|
||||
version="1.4.14",
|
||||
)
|
||||
|
||||
nats_cmd.return_value = "ok"
|
||||
get_exe.return_value = "https://exe.tacticalrmm.io"
|
||||
r = agent_update(agent64_sign.pk, codesign.token) # type: ignore
|
||||
self.assertEqual(r, "created")
|
||||
nats_cmd.assert_called_with(
|
||||
{
|
||||
"func": "agentupdate",
|
||||
"payload": {
|
||||
"url": f"https://exe.tacticalrmm.io/api/v1/winagents/?version={settings.LATEST_AGENT_VER}&arch=64&token=testtoken123", # type: ignore
|
||||
"version": settings.LATEST_AGENT_VER,
|
||||
"inno": f"winagent-v{settings.LATEST_AGENT_VER}.exe",
|
||||
},
|
||||
},
|
||||
wait=False,
|
||||
)
|
||||
action = PendingAction.objects.get(agent__pk=agent64_sign.pk)
|
||||
self.assertEqual(action.action_type, "agentupdate")
|
||||
self.assertEqual(action.status, "pending")
|
||||
|
||||
# test __with__ code signing (32 bit)
|
||||
agent32_sign = baker.make_recipe(
|
||||
"agents.agent",
|
||||
operating_system="Windows 10 Pro, 32 bit (build 19041.450)",
|
||||
version="1.4.14",
|
||||
)
|
||||
|
||||
nats_cmd.return_value = "ok"
|
||||
get_exe.return_value = "https://exe.tacticalrmm.io"
|
||||
r = agent_update(agent32_sign.pk, codesign.token) # type: ignore
|
||||
self.assertEqual(r, "created")
|
||||
nats_cmd.assert_called_with(
|
||||
{
|
||||
"func": "agentupdate",
|
||||
"payload": {
|
||||
"url": f"https://exe.tacticalrmm.io/api/v1/winagents/?version={settings.LATEST_AGENT_VER}&arch=32&token=testtoken123", # type: ignore
|
||||
"version": settings.LATEST_AGENT_VER,
|
||||
"inno": f"winagent-v{settings.LATEST_AGENT_VER}-x86.exe",
|
||||
},
|
||||
},
|
||||
wait=False,
|
||||
)
|
||||
action = PendingAction.objects.get(agent__pk=agent32_sign.pk)
|
||||
self.assertEqual(action.action_type, "agentupdate")
|
||||
self.assertEqual(action.status, "pending")
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ logger.configure(**settings.LOG_CONFIG)
|
||||
|
||||
@api_view()
|
||||
def get_agent_versions(request):
|
||||
agents = Agent.objects.only("pk")
|
||||
agents = Agent.objects.prefetch_related("site").only("pk", "hostname")
|
||||
return Response(
|
||||
{
|
||||
"versions": [settings.LATEST_AGENT_VER],
|
||||
|
||||
@@ -633,12 +633,15 @@ class Check(BaseAuditModel):
|
||||
if self.error_threshold:
|
||||
text += f" Error Threshold: {self.error_threshold}%"
|
||||
|
||||
percent_used = [
|
||||
d["percent"] for d in self.agent.disks if d["device"] == self.disk
|
||||
][0]
|
||||
percent_free = 100 - percent_used
|
||||
try:
|
||||
percent_used = [
|
||||
d["percent"] for d in self.agent.disks if d["device"] == self.disk
|
||||
][0]
|
||||
percent_free = 100 - percent_used
|
||||
|
||||
body = subject + f" - Free: {percent_free}%, {text}"
|
||||
body = subject + f" - Free: {percent_free}%, {text}"
|
||||
except:
|
||||
body = subject + f" - Disk {self.disk} does not exist"
|
||||
|
||||
elif self.check_type == "script":
|
||||
|
||||
@@ -710,11 +713,15 @@ class Check(BaseAuditModel):
|
||||
if self.error_threshold:
|
||||
text += f" Error Threshold: {self.error_threshold}%"
|
||||
|
||||
percent_used = [
|
||||
d["percent"] for d in self.agent.disks if d["device"] == self.disk
|
||||
][0]
|
||||
percent_free = 100 - percent_used
|
||||
body = subject + f" - Free: {percent_free}%, {text}"
|
||||
try:
|
||||
percent_used = [
|
||||
d["percent"] for d in self.agent.disks if d["device"] == self.disk
|
||||
][0]
|
||||
percent_free = 100 - percent_used
|
||||
body = subject + f" - Free: {percent_free}%, {text}"
|
||||
except:
|
||||
body = subject + f" - Disk {self.disk} does not exist"
|
||||
|
||||
elif self.check_type == "script":
|
||||
body = subject + f" - Return code: {self.retcode}"
|
||||
elif self.check_type == "ping":
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import CoreSettings, CustomField
|
||||
from .models import CoreSettings, CustomField, CodeSignToken
|
||||
|
||||
admin.site.register(CoreSettings)
|
||||
admin.site.register(CustomField)
|
||||
admin.site.register(CodeSignToken)
|
||||
|
||||
20
api/tacticalrmm/core/migrations/0019_codesigntoken.py
Normal file
20
api/tacticalrmm/core/migrations/0019_codesigntoken.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 3.2 on 2021-04-13 05:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0018_auto_20210329_1709'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CodeSignToken',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('token', models.CharField(blank=True, max_length=255, null=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -266,3 +266,16 @@ class CustomField(models.Model):
|
||||
return self.default_value_bool
|
||||
else:
|
||||
return self.default_value_string
|
||||
|
||||
|
||||
class CodeSignToken(models.Model):
|
||||
token = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk and CodeSignToken.objects.exists():
|
||||
raise ValidationError("There can only be one CodeSignToken instance")
|
||||
|
||||
super(CodeSignToken, self).save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return "Code signing token"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytz
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import CoreSettings, CustomField
|
||||
from .models import CoreSettings, CustomField, CodeSignToken
|
||||
|
||||
|
||||
class CoreSettingsSerializer(serializers.ModelSerializer):
|
||||
@@ -27,3 +27,9 @@ class CustomFieldSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = CustomField
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class CodeSignTokenSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = CodeSignToken
|
||||
fields = "__all__"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import requests
|
||||
from unittest.mock import patch
|
||||
|
||||
from channels.db import database_sync_to_async
|
||||
@@ -12,6 +13,28 @@ from .serializers import CustomFieldSerializer
|
||||
from .tasks import core_maintenance_tasks
|
||||
|
||||
|
||||
class TestCodeSign(TacticalTestCase):
|
||||
def setUp(self):
|
||||
self.setup_coresettings()
|
||||
self.authenticate()
|
||||
self.url = "/core/codesign/"
|
||||
|
||||
def test_get_codesign(self):
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.check_not_authenticated("get", self.url)
|
||||
|
||||
@patch("requests.post")
|
||||
def test_edit_codesign_timeout(self, mock_post):
|
||||
mock_post.side_effect = requests.exceptions.ConnectionError()
|
||||
data = {"token": "token123"}
|
||||
r = self.client.patch(self.url, data, format="json")
|
||||
self.assertEqual(r.status_code, 400)
|
||||
|
||||
self.check_not_authenticated("patch", self.url)
|
||||
|
||||
|
||||
class TestConsumers(TacticalTestCase):
|
||||
def setUp(self):
|
||||
self.setup_coresettings()
|
||||
|
||||
@@ -12,4 +12,5 @@ urlpatterns = [
|
||||
path("servermaintenance/", views.server_maintenance),
|
||||
path("customfields/", views.GetAddCustomFields.as_view()),
|
||||
path("customfields/<int:pk>/", views.GetUpdateDeleteCustomFields.as_view()),
|
||||
path("codesign/", views.CodeSign.as_view()),
|
||||
]
|
||||
|
||||
@@ -11,8 +11,12 @@ from rest_framework.views import APIView
|
||||
|
||||
from tacticalrmm.utils import notify_error
|
||||
|
||||
from .models import CoreSettings, CustomField
|
||||
from .serializers import CoreSettingsSerializer, CustomFieldSerializer
|
||||
from .models import CoreSettings, CustomField, CodeSignToken
|
||||
from .serializers import (
|
||||
CoreSettingsSerializer,
|
||||
CustomFieldSerializer,
|
||||
CodeSignTokenSerializer,
|
||||
)
|
||||
|
||||
|
||||
class UploadMeshAgent(APIView):
|
||||
@@ -65,6 +69,8 @@ def dashboard_info(request):
|
||||
"dbl_click_action": request.user.agent_dblclick_action,
|
||||
"default_agent_tbl_tab": request.user.default_agent_tbl_tab,
|
||||
"client_tree_sort": request.user.client_tree_sort,
|
||||
"client_tree_splitter": request.user.client_tree_splitter,
|
||||
"loading_bar_color": request.user.loading_bar_color,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -177,3 +183,48 @@ class GetUpdateDeleteCustomFields(APIView):
|
||||
get_object_or_404(CustomField, pk=pk).delete()
|
||||
|
||||
return Response("ok")
|
||||
|
||||
|
||||
class CodeSign(APIView):
|
||||
def get(self, request):
|
||||
token = CodeSignToken.objects.first()
|
||||
return Response(CodeSignTokenSerializer(token).data)
|
||||
|
||||
def patch(self, request):
|
||||
import requests
|
||||
|
||||
errors = []
|
||||
for url in settings.EXE_GEN_URLS:
|
||||
try:
|
||||
r = requests.post(
|
||||
f"{url}/api/v1/checktoken",
|
||||
json={"token": request.data["token"]},
|
||||
headers={"Content-type": "application/json"},
|
||||
timeout=15,
|
||||
)
|
||||
except Exception as e:
|
||||
errors.append(str(e))
|
||||
else:
|
||||
errors = []
|
||||
break
|
||||
|
||||
if errors:
|
||||
return notify_error(", ".join(errors))
|
||||
|
||||
if r.status_code == 400 or r.status_code == 401: # type: ignore
|
||||
return notify_error(r.json()["ret"]) # type: ignore
|
||||
elif r.status_code == 200: # type: ignore
|
||||
t = CodeSignToken.objects.first()
|
||||
if t is None:
|
||||
CodeSignToken.objects.create(token=request.data["token"])
|
||||
else:
|
||||
serializer = CodeSignTokenSerializer(instance=t, data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response("Token was saved")
|
||||
|
||||
try:
|
||||
ret = r.json()["ret"] # type: ignore
|
||||
except:
|
||||
ret = "Something went wrong"
|
||||
return notify_error(ret)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"guid": "6820cb5e-5a7f-4d9b-8c22-d54677e3cc04",
|
||||
"filename": "Win_Clear_Firefox_Cache.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Clear Firefox Cache",
|
||||
"name": "Firefox - Clean Cache",
|
||||
"description": "This script will clean up Mozilla Firefox for all users.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Browsers"
|
||||
@@ -12,7 +12,7 @@
|
||||
"guid": "3ff6a386-11d1-4f9d-8cca-1b0563bb6443",
|
||||
"filename": "Win_Clear_Google_Chrome_Cache.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Clear Google Chrome Cache",
|
||||
"name": "Chrome - Clear Cache for All Users",
|
||||
"description": "This script will clean up Google Chrome for all users.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Browsers"
|
||||
@@ -21,7 +21,7 @@
|
||||
"guid": "be1de837-f677-4ac5-aa0c-37a0fc9991fc",
|
||||
"filename": "Win_Install_Adobe_Reader.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Install Adobe Reader DC",
|
||||
"name": "Adobe Reader DC - Install",
|
||||
"description": "Installs Adobe Reader DC.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):3rd Party Software>Chocolatey"
|
||||
@@ -30,7 +30,7 @@
|
||||
"guid": "2ee134d5-76aa-4160-b334-a1efbc62079f",
|
||||
"filename": "Win_Install_Duplicati.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Install Duplicati",
|
||||
"name": "Duplicati - Install",
|
||||
"description": "This script installs Duplicati 2.0.5.1 as a service.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):3rd Party Software"
|
||||
@@ -39,7 +39,7 @@
|
||||
"guid": "81cc5bcb-01bf-4b0c-89b9-0ac0f3fe0c04",
|
||||
"filename": "Win_Reset_Windows_Update.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Reset Windows Update",
|
||||
"name": "Windows Update - Reset",
|
||||
"description": "This script will reset all of the Windows Updates components to DEFAULT SETTINGS.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Updates"
|
||||
@@ -48,7 +48,7 @@
|
||||
"guid": "8db87ff0-a9b4-4d9d-bc55-377bbcb85b6d",
|
||||
"filename": "Win_Start_Cleanup.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Cleanup C: drive",
|
||||
"name": "Disk - Cleanup C: drive",
|
||||
"description": "Cleans the C: drive's Window Temperary files, Windows SoftwareDistribution folder, the local users Temperary folder, IIS logs (if applicable) and empties the recycling bin. All deleted files will go into a log transcript in $env:TEMP. By default this script leaves files that are newer than 7 days old however this variable can be edited.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
@@ -57,7 +57,7 @@
|
||||
"guid": "2f28e8c1-ae0f-4b46-a826-f513974526a3",
|
||||
"filename": "Win_Defender_FullScan_Background.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Windows Defender Full Scan",
|
||||
"name": "Defender - Full Scan",
|
||||
"description": "Runs a Windows Defender Full background scan.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security>Antivirus"
|
||||
@@ -66,7 +66,7 @@
|
||||
"guid": "adf81ddb-3b77-415c-a89b-2ccc826b5aa7",
|
||||
"filename": "Win_Defender_QuickScan_Background.ps1",
|
||||
"submittedBy": "https://github.com/Omnicef",
|
||||
"name": "Windows Defender Quick Scan",
|
||||
"name": "Defender - Quick Scan",
|
||||
"description": "Runs a Quick Scan using Windows Defender in the Background.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security>Antivirus"
|
||||
@@ -75,7 +75,7 @@
|
||||
"guid": "3c46290b-85db-4cd2-93a2-943c8c93b3b1",
|
||||
"filename": "Speedtest.py",
|
||||
"submittedBy": "https://github.com/wh1te909",
|
||||
"name": "Speed Test",
|
||||
"name": "Network - Speed Test",
|
||||
"description": "Runs a Speed Test using Python",
|
||||
"shell": "python",
|
||||
"category": "TRMM (Win):Network"
|
||||
@@ -84,7 +84,7 @@
|
||||
"guid": "9d34f482-1f0c-4b2f-b65f-a9cf3c13ef5f",
|
||||
"filename": "Win_Rename_Installed_App.ps1",
|
||||
"submittedBy": "https://github.com/bradhawkins85",
|
||||
"name": "Rename Tactical RMM Agent",
|
||||
"name": "TacticalRMM Agent Rename",
|
||||
"description": "Updates the DisplayName registry entry for the Tactical RMM windows agent to your desired name. This script takes 1 required argument: the name you wish to set.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):TacticalRMM Related"
|
||||
@@ -93,7 +93,7 @@
|
||||
"guid": "525ae965-1dcf-4c17-92b3-5da3cf6819f5",
|
||||
"filename": "Win_Bitlocker_Encrypted_Drive_c.ps1",
|
||||
"submittedBy": "https://github.com/ThatsNASt",
|
||||
"name": "Check C Drive for Bitlocker Status",
|
||||
"name": "Bitlocker - Check C Drive for Status",
|
||||
"description": "Runs a check on drive C for Bitlocker status.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Storage"
|
||||
@@ -111,25 +111,52 @@
|
||||
"guid": "9e5769c1-3873-4941-bf70-e851e0afbd6d",
|
||||
"filename": "Win_Bitlocker_Retrieve_Status_Report.ps1",
|
||||
"submittedBy": "https://github.com/ThatsNASt",
|
||||
"name": "Retreive Bitlocker Status Report",
|
||||
"name": "Bitlocker - Retrieve Status Report",
|
||||
"description": "Retreives a Bitlocker status report.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Storage"
|
||||
},
|
||||
{
|
||||
"guid": "72b93487-0266-43f0-97cc-03d4c7ee0b44",
|
||||
"filename": "Win_Bitlocker_Get_Recovery_Keys.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Bitlocker - Get Recovery Keys",
|
||||
"description": "Retreives a Bitlocker Recovery Keys",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Storage"
|
||||
},
|
||||
{
|
||||
"guid": "cfa14c28-4dfc-4d4e-95ee-a380652e058d",
|
||||
"filename": "Win_Bios_Check.ps1",
|
||||
"submittedBy": "https://github.com/ThatsNASt",
|
||||
"name": "Check BIOS Information",
|
||||
"name": "BIOS - Check Information",
|
||||
"description": "Retreives and reports on BIOS make, version, and date.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Hardware"
|
||||
},
|
||||
{
|
||||
"guid": "e1c27982-b955-4766-85b6-d92527a177cf",
|
||||
"filename": "Win_Hardware_Monitor_Get_Info.ps1",
|
||||
"submittedBy": "https://github.com/MaxAnderson95/",
|
||||
"name": "Monitor - Get Info",
|
||||
"description": "Retreives and reports on Monitor info: Manufacturer, Model, Serial",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Hardware"
|
||||
},
|
||||
{
|
||||
"guid": "ae231ac4-b01f-4a39-a9d2-3d817af75260",
|
||||
"filename": "Win_Hardware_RAM_Status.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "RAM - Check Information",
|
||||
"description": "Retreives and reports on RAM info: DIMM's, total memory, slots total and used",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Hardware"
|
||||
},
|
||||
{
|
||||
"guid": "95a2ee6f-b89b-4551-856e-3081b041caa7",
|
||||
"filename": "Win_Reset_High_Performance_Power_Profile_to_Defaults.ps1",
|
||||
"submittedBy": "https://github.com/azulskyknight",
|
||||
"name": "Reset High Perf Power Profile",
|
||||
"name": "Power Profile - Reset High Perf Power Profile to defaults",
|
||||
"description": "Resets monitor, disk, standby, and hibernate timers in the default High Performance power profile to their default values. It also re-indexes the AC and DC power profiles into their default order.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Power"
|
||||
@@ -138,7 +165,7 @@
|
||||
"guid": "2cbd30b0-84dd-4388-a36d-2e2e980f1a3e",
|
||||
"filename": "Win_Set_High_Performance_Power_Profile.ps1",
|
||||
"submittedBy": "https://github.com/azulskyknight",
|
||||
"name": "Set High Perf Power Profile",
|
||||
"name": "Power Profile - Set High Performance",
|
||||
"description": "Sets the High Performance Power profile to the active power profile. Use this to keep machines from falling asleep.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Power"
|
||||
@@ -156,7 +183,7 @@
|
||||
"guid": "375323e5-cac6-4f35-a304-bb7cef35902d",
|
||||
"filename": "Win_Disk_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Check Disk Hardware Health (using Event Viewer errors)",
|
||||
"name": "Disk Hardware Health Check (using Event Viewer errors)",
|
||||
"description": "Checks local disks for errors reported in event viewer within the last 24 hours",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Hardware"
|
||||
@@ -165,7 +192,7 @@
|
||||
"guid": "7c14beb4-d1c3-41aa-8e70-92a267d6e080",
|
||||
"filename": "Win_Duplicati_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Check Duplicati",
|
||||
"name": "Duplicati - Check",
|
||||
"description": "Checks Duplicati Backup is running properly over the last 24 hours",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):3rd Party Software"
|
||||
@@ -174,7 +201,7 @@
|
||||
"guid": "da51111c-aff6-4d87-9d76-0608e1f67fe5",
|
||||
"filename": "Win_Defender_Enable.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Enable Windows Defender",
|
||||
"name": "Defender - Enable",
|
||||
"description": "Enables Windows Defender and sets preferences",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security>Antivirus"
|
||||
@@ -183,8 +210,8 @@
|
||||
"guid": "a223d03a-e22e-40e0-94f2-92dd8c481d14",
|
||||
"filename": "Win_Open_SSH_Server_Install.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Install SSH",
|
||||
"description": "Installs and enabled OpenSSH Server",
|
||||
"name": "SSH - Install Feature and Enable",
|
||||
"description": "Installs and enabled OpenSSH Server Feature in Win10",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Windows Features"
|
||||
},
|
||||
@@ -192,7 +219,7 @@
|
||||
"guid": "2435297a-6263-4e90-8688-1847400d0e22",
|
||||
"filename": "Win_RDP_enable.bat",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Enable RDP",
|
||||
"name": "RDP - Enable",
|
||||
"description": "Enables RDP",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Windows Features"
|
||||
@@ -210,16 +237,25 @@
|
||||
"guid": "a821975c-60df-4d58-8990-6cf8a55b4ee0",
|
||||
"filename": "Win_Sync_Time.bat",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Sync DC Time",
|
||||
"name": "ADDC - Sync DC Time",
|
||||
"description": "Syncs time with domain controller",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Active Directory"
|
||||
},
|
||||
{
|
||||
"guid": "b6b9912f-4274-4162-99cc-9fd47fbcb292",
|
||||
"filename": "Win_ADDC_Sync_Start.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "ADDC - Sync AD",
|
||||
"description": "Trigger AD Sync on domain controller",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Active Directory"
|
||||
},
|
||||
{
|
||||
"guid": "b720e320-7755-4c89-9992-e1a6c43699ed",
|
||||
"filename": "Win_Defender_Clear_Logs.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Clear Defender Logs",
|
||||
"name": "Defender - Clear Logs",
|
||||
"description": "Clears Windows Defender Logs",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security>Antivirus"
|
||||
@@ -228,7 +264,7 @@
|
||||
"guid": "d980fda3-a068-47eb-8495-1aab07a24e64",
|
||||
"filename": "Win_Defender_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Defender Status",
|
||||
"name": "Defender - Status",
|
||||
"description": "This will check for Malware, Antispyware, that Windows Defender is Healthy, last scan etc within the last 24 hours",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security>Antivirus"
|
||||
@@ -237,11 +273,20 @@
|
||||
"guid": "9956e936-6fdb-4488-a9d8-8b274658037f",
|
||||
"filename": "Win_Disable_Fast_Startup.bat",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Disable Fast Startup",
|
||||
"name": "Power - Fast Startup Disable",
|
||||
"description": "Disables Faststartup on Windows 10",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Power"
|
||||
},
|
||||
{
|
||||
"guid": "f628a02b-16c3-4ab5-b788-dec5bc2af1d9",
|
||||
"filename": "Win_Power_Disable_Hibernation.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Power - Hibernate Disable",
|
||||
"description": "Disables Hibernation",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Power"
|
||||
},
|
||||
{
|
||||
"guid": "2472bbaf-1941-4722-8a58-d1dd0f528801",
|
||||
"filename": "Win_Update_Tactical_Exclusion.ps1",
|
||||
@@ -255,7 +300,7 @@
|
||||
"guid": "b253dc76-41a0-48ca-9cea-bee4277402c4",
|
||||
"filename": "Win_Display_Message_To_User.ps1",
|
||||
"submittedBy": "https://github.com/bradhawkins85",
|
||||
"name": "Display Message To User",
|
||||
"name": "Message Popup To User",
|
||||
"description": "Displays a popup message to the currently logged on user",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
@@ -264,7 +309,7 @@
|
||||
"guid": "19224d21-bd39-44bc-b9cf-8f1ba3ca9c11",
|
||||
"filename": "Win_Antivirus_Verify.ps1",
|
||||
"submittedBy": "https://github.com/beejayzed",
|
||||
"name": "Verify Antivirus Status",
|
||||
"name": "Antivirus - Verify Status",
|
||||
"description": "Verify and display status for all installed Antiviruses",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security>Antivirus"
|
||||
@@ -273,7 +318,7 @@
|
||||
"guid": "f88c5c52-c6fe-44db-b727-b7912a4279ed",
|
||||
"filename": "Win_Create_All_User_Logon_Script.ps1",
|
||||
"submittedBy": "https://github.com/nr-plaxon",
|
||||
"name": "Create User Logon Script",
|
||||
"name": "Template Example - Create User Logon Script",
|
||||
"description": "Creates a powershell script that runs at logon of any user on the machine in the security context of the user.",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
@@ -291,7 +336,7 @@
|
||||
"guid": "fff8024d-d72e-4457-84fa-6c780f69a16f",
|
||||
"filename": "Win_AD_Check_And_Enable_AD_Recycle_Bin.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "AD - Check and Enable AD Recycle Bin",
|
||||
"name": "ADDC - Check and Enable AD Recycle Bin",
|
||||
"description": "Only run on Domain Controllers, checks for Active Directory Recycle Bin and enables if not already enabled",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Active Directory"
|
||||
@@ -300,11 +345,38 @@
|
||||
"guid": "71090fc4-faa6-460b-adb0-95d7863544e1",
|
||||
"filename": "Win_Check_Events_for_Bluescreens.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Event Viewer - Check for Bluescreens",
|
||||
"description": "This will check for Bluescreen events on your system",
|
||||
"name": "Event Viewer - Bluescreen Notification",
|
||||
"description": "Event Viewer Monitor - Notify Bluescreen events on your system",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Monitoring"
|
||||
},
|
||||
{
|
||||
"guid": "8373846f-facc-49b9-9891-3a780a394c89",
|
||||
"filename": "Win_Local_User_Created_Monitor.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Event Viewer - New User Notification",
|
||||
"description": "Event Viewer Monitor - Notify when new Local user is created",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Monitoring"
|
||||
},
|
||||
{
|
||||
"guid": "65e5cef1-8338-4180-a0bc-cd54e62de690",
|
||||
"filename": "Win_Task_Scheduler_New_Items_Monitor.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Event Viewer - Task Scheduler New Item Notification",
|
||||
"description": "Event Viewer Monitor - Notify when new Task Scheduler item is created",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Monitoring"
|
||||
},
|
||||
{
|
||||
"guid": "08ca81f2-f044-4dfc-ad47-090b19b19d76",
|
||||
"filename": "Win_User_Logged_in_with_Temp_Profile.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "User Logged in with temp profile check",
|
||||
"description": "Check if users are logged in with a temp profile",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
},
|
||||
{
|
||||
"guid": "5d905886-9eb1-4129-8b81-a013f842eb24",
|
||||
"filename": "Win_Rename_Computer.ps1",
|
||||
@@ -319,8 +391,8 @@
|
||||
"guid": "f396dae2-c768-45c5-bd6c-176e56ed3614",
|
||||
"filename": "Win_Finish_updates_and_restart.ps1",
|
||||
"submittedBy": "https://github.com/tremor021",
|
||||
"name": "Finish updates and restart",
|
||||
"description": "Finish installing updates and restart PC",
|
||||
"name": "Updates - Finish and restart",
|
||||
"description": "Finish installing Windows updates and restart PC",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
},
|
||||
@@ -328,14 +400,14 @@
|
||||
"guid": "63f89be0-a9c9-4c61-9b55-bce0b28b90b2",
|
||||
"filename": "Win_Finish_updates_and_shutdown.ps1",
|
||||
"submittedBy": "https://github.com/tremor021",
|
||||
"name": "Finish updates and shutdown",
|
||||
"description": "Finish installing updates and shutdown PC",
|
||||
"name": "Updates - Finish and Shutdown",
|
||||
"description": "Finish installing Windows updates and shutdown PC",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
},
|
||||
{
|
||||
"guid": "e09895d5-ca13-44a2-a38c-6e77c740f0e8",
|
||||
"filename": "ScreenConnectAIO.ps1",
|
||||
"filename": "Win_ScreenConnectAIO.ps1",
|
||||
"submittedBy": "https://github.com/bradhawkins85",
|
||||
"name": "ScreenConnect AIO",
|
||||
"description": "Install, Uninstall, Start and Stop ScreenConnect Access Agent",
|
||||
@@ -347,5 +419,164 @@
|
||||
"default_timeout": "90",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):3rd Party Software"
|
||||
},
|
||||
{
|
||||
"guid": "3abbb62a-3757-492c-8979-b4fc6174845d",
|
||||
"filename": "Win_Disable_AutoRun.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Autorun - Disable",
|
||||
"description": "Disable Autorun System Wide",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Other",
|
||||
"default_timeout": "30"
|
||||
},
|
||||
{
|
||||
"guid": "4a11877a-7555-494c-ac74-29d6df3c1989",
|
||||
"filename": "Win_Disable_Cortana.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Cortana - Disable",
|
||||
"description": "Disable Cortana System Wide",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Other",
|
||||
"default_timeout": "30"
|
||||
},
|
||||
{
|
||||
"guid": "28ef1387-dd4f-4bab-b042-26250914e370",
|
||||
"filename": "Win_WOL_Enable_Status.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Network WoL - Enable function",
|
||||
"description": "Wake on Lan enable on Dell, HP, Lenovo",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Network",
|
||||
"default_timeout": "90"
|
||||
},
|
||||
{
|
||||
"guid": "685d5432-0b84-46d5-98e8-3ec2054150fe",
|
||||
"filename": "Win_WOL_Test_State.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Network WoL - Test State",
|
||||
"description": "Wake on Lan test status",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Network",
|
||||
"default_timeout": "90"
|
||||
},
|
||||
{
|
||||
"guid": "6ce5682a-49db-4c0b-9417-609cf905ac43",
|
||||
"filename": "Win_Win10_Change_Key_and_Activate.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "Product Key in Win10 Change and Activate",
|
||||
"description": "Insert new product key and Activate. Requires 1 parameter the product key you want to use",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other",
|
||||
"default_timeout": "90"
|
||||
},
|
||||
{
|
||||
"guid": "83f6c6ea-6120-4fd3-bec8-d3abc505dcdf",
|
||||
"filename": "Win_TRMM_Start_Menu_Delete_Shortcut.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "TRMM Delete Start Menu Shortcut for App",
|
||||
"description": "Tactical RMM delete its application shortcut that's installed in the start menu",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):TacticalRMM Related",
|
||||
"default_timeout": "10"
|
||||
},
|
||||
{
|
||||
"guid": "60130fca-7636-446e-acd7-cc5d29d609c2",
|
||||
"filename": "Win_Firewall_Check_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Windows Firewall - Check Status",
|
||||
"description": "Windows Firewall - Check state, report status",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Network"
|
||||
},
|
||||
{
|
||||
"guid": "93379675-c01c-433f-87df-a11597c959f0",
|
||||
"filename": "Win_UAC_Check_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Windows UAC - Check Status",
|
||||
"description": "Windows UAC - Report status",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Security"
|
||||
},
|
||||
{
|
||||
"guid": "7ea6a11a-05c0-4151-b5c1-cb8af029299f",
|
||||
"filename": "Win_AzureAD_Check_Connection_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Azure AD - Check Status",
|
||||
"description": "Azure AD - Check if joined or not",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Azure>AD"
|
||||
},
|
||||
{
|
||||
"guid": "7d81859a-1ba3-42b0-8664-29844f0dd765",
|
||||
"filename": "Win_Azure_Mars_Cloud_Backup_Status.ps1",
|
||||
"submittedBy": "https://github.com/dinger1986",
|
||||
"name": "Azure - Mars Cloud backup Status",
|
||||
"description": "Azure - Mars Cloud backup Check Status",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Azure>Backup"
|
||||
},
|
||||
{
|
||||
"guid": "e18c64d0-b783-4b52-b44b-9bb7592b439b",
|
||||
"filename": "Win_FileSystem_Enable_Long_Paths.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "File System - Enable Long Paths",
|
||||
"description": "Enables NTFS Long paths greater than 260 characters",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Storage"
|
||||
},
|
||||
{
|
||||
"guid": "c6252ca8-5172-42ea-9114-e447f80868f5",
|
||||
"filename": "Win_USB_Disable_Access.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "USB - Disable Access",
|
||||
"description": "USB - Disable Plugged in USB devices",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Storage"
|
||||
},
|
||||
{
|
||||
"guid": "3785952f-69fb-4bda-b2fe-5e3e8642738a",
|
||||
"filename": "Win_USB_Enable_Access.bat",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "USB - Enable Access",
|
||||
"description": "USB - Enable Plugged in USB devices",
|
||||
"shell": "cmd",
|
||||
"category": "TRMM (Win):Storage"
|
||||
},
|
||||
{
|
||||
"guid": "c6014da2-b188-4e1b-b96a-e3440ade3a6a",
|
||||
"filename": "Win_RecycleBin_Empty.ps1",
|
||||
"submittedBy": "https://github.com/silversword411",
|
||||
"name": "File System - Empty Recycle Bin",
|
||||
"description": "Empty the recycle bin",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Storage"
|
||||
},
|
||||
{
|
||||
"guid": "57997ec7-b293-4fd5-9f90-a25426d0eb90",
|
||||
"filename": "Win_Get_Computer_Users.ps1",
|
||||
"submittedBy": "https://github.com/tremor021",
|
||||
"name": "Get Computer Users",
|
||||
"description": "Get list of computer users and show which one is enabled",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
},
|
||||
{
|
||||
"guid": "77da9c87-5a7a-4ba1-bdde-3eeb3b01d62d",
|
||||
"filename": "Win_Set_Network_To_Private.ps1",
|
||||
"submittedBy": "https://github.com/tremor021",
|
||||
"name": "Set Network To Private",
|
||||
"description": "Sets current network type to Private",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Network"
|
||||
},
|
||||
{
|
||||
"guid": "768f42d5-7b45-45ed-8233-254ae537aaa2",
|
||||
"filename": "Win_TaskScheduler_Add_Task.ps1",
|
||||
"submittedBy": "https://github.com/tremor021",
|
||||
"name": "Add task to TaskScheduler",
|
||||
"description": "Add a task to Task Scheduler, needs editing",
|
||||
"shell": "powershell",
|
||||
"category": "TRMM (Win):Other"
|
||||
}
|
||||
]
|
||||
18
api/tacticalrmm/scripts/migrations/0008_script_guid.py
Normal file
18
api/tacticalrmm/scripts/migrations/0008_script_guid.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.1.7 on 2021-04-15 02:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scripts', '0007_script_args'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='script',
|
||||
name='guid',
|
||||
field=models.CharField(blank=True, max_length=64, null=True),
|
||||
),
|
||||
]
|
||||
@@ -23,6 +23,7 @@ logger.configure(**settings.LOG_CONFIG)
|
||||
|
||||
|
||||
class Script(BaseAuditModel):
|
||||
guid = name = models.CharField(max_length=64, null=True, blank=True)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(null=True, blank=True)
|
||||
filename = models.CharField(max_length=255) # deprecated
|
||||
@@ -78,9 +79,7 @@ class Script(BaseAuditModel):
|
||||
|
||||
for script in info:
|
||||
if os.path.exists(os.path.join(scripts_dir, script["filename"])):
|
||||
s = cls.objects.filter(script_type="builtin").filter(
|
||||
name=script["name"]
|
||||
)
|
||||
s = cls.objects.filter(script_type="builtin", guid=script["guid"])
|
||||
|
||||
category = (
|
||||
script["category"] if "category" in script.keys() else "Community"
|
||||
@@ -120,6 +119,46 @@ class Script(BaseAuditModel):
|
||||
"args",
|
||||
]
|
||||
)
|
||||
|
||||
# check if script was added without a guid
|
||||
elif cls.objects.filter(
|
||||
script_type="builtin", name=script["name"]
|
||||
).exists():
|
||||
s = cls.objects.get(script_type="builtin", name=script["name"])
|
||||
|
||||
if not s.guid:
|
||||
print(f"Updating GUID for: {script['name']}")
|
||||
s.guid = script["guid"]
|
||||
s.name = script["name"]
|
||||
s.description = script["description"]
|
||||
s.category = category
|
||||
s.shell = script["shell"]
|
||||
s.default_timeout = default_timeout
|
||||
s.args = args
|
||||
|
||||
with open(
|
||||
os.path.join(scripts_dir, script["filename"]), "rb"
|
||||
) as f:
|
||||
script_bytes = (
|
||||
f.read().decode("utf-8").encode("ascii", "ignore")
|
||||
)
|
||||
s.code_base64 = base64.b64encode(script_bytes).decode(
|
||||
"ascii"
|
||||
)
|
||||
|
||||
s.save(
|
||||
update_fields=[
|
||||
"guid",
|
||||
"name",
|
||||
"description",
|
||||
"category",
|
||||
"default_timeout",
|
||||
"code_base64",
|
||||
"shell",
|
||||
"args",
|
||||
]
|
||||
)
|
||||
|
||||
else:
|
||||
print(f"Adding new community script: {script['name']}")
|
||||
|
||||
@@ -131,6 +170,7 @@ class Script(BaseAuditModel):
|
||||
|
||||
cls(
|
||||
code_base64=code_base64,
|
||||
guid=script["guid"],
|
||||
name=script["name"],
|
||||
description=script["description"],
|
||||
filename=script["filename"],
|
||||
@@ -141,6 +181,9 @@ class Script(BaseAuditModel):
|
||||
args=args,
|
||||
).save()
|
||||
|
||||
# delete community scripts that had their name changed
|
||||
cls.objects.filter(script_type="builtin", guid=None).delete()
|
||||
|
||||
@staticmethod
|
||||
def serialize(script):
|
||||
# serializes the script and returns json
|
||||
|
||||
@@ -245,12 +245,39 @@ class TestScriptViews(TacticalTestCase):
|
||||
|
||||
Script.load_community_scripts()
|
||||
|
||||
community_scripts = Script.objects.filter(script_type="builtin").count()
|
||||
self.assertEqual(len(info), community_scripts)
|
||||
community_scripts_count = Script.objects.filter(script_type="builtin").count()
|
||||
if len(info) != community_scripts_count:
|
||||
raise Exception(
|
||||
f"There are {len(info)} scripts in json file but only {community_scripts_count} in database"
|
||||
)
|
||||
|
||||
# test updating already added community scripts
|
||||
Script.load_community_scripts()
|
||||
self.assertEqual(len(info), community_scripts)
|
||||
community_scripts_count2 = Script.objects.filter(script_type="builtin").count()
|
||||
self.assertEqual(len(info), community_scripts_count2)
|
||||
|
||||
def test_community_script_has_jsonfile_entry(self):
|
||||
with open(
|
||||
os.path.join(settings.BASE_DIR, "scripts/community_scripts.json")
|
||||
) as f:
|
||||
info = json.load(f)
|
||||
|
||||
filenames = [i["filename"] for i in info]
|
||||
|
||||
# normal
|
||||
if not settings.DOCKER_BUILD:
|
||||
scripts_dir = os.path.join(Path(settings.BASE_DIR).parents[1], "scripts")
|
||||
# docker
|
||||
else:
|
||||
scripts_dir = settings.SCRIPTS_DIR
|
||||
|
||||
with os.scandir(scripts_dir) as it:
|
||||
for f in it:
|
||||
if not f.name.startswith(".") and f.is_file():
|
||||
if f.name not in filenames:
|
||||
raise Exception(
|
||||
f"{f.name} is missing an entry in community_scripts.json"
|
||||
)
|
||||
|
||||
def test_script_filenames_do_not_contain_spaces(self):
|
||||
with open(
|
||||
@@ -259,4 +286,5 @@ class TestScriptViews(TacticalTestCase):
|
||||
info = json.load(f)
|
||||
for script in info:
|
||||
fn: str = script["filename"]
|
||||
self.assertTrue(" " not in fn)
|
||||
if " " in fn:
|
||||
raise Exception(f"{fn} must not contain spaces in filename")
|
||||
|
||||
@@ -15,16 +15,16 @@ EXE_DIR = os.path.join(BASE_DIR, "tacticalrmm/private/exe")
|
||||
AUTH_USER_MODEL = "accounts.User"
|
||||
|
||||
# latest release
|
||||
TRMM_VERSION = "0.5.1"
|
||||
TRMM_VERSION = "0.6.0"
|
||||
|
||||
# bump this version everytime vue code is changed
|
||||
# to alert user they need to manually refresh their browser
|
||||
APP_VER = "0.0.127"
|
||||
APP_VER = "0.0.129"
|
||||
|
||||
# https://github.com/wh1te909/rmmagent
|
||||
LATEST_AGENT_VER = "1.4.13"
|
||||
LATEST_AGENT_VER = "1.5.0"
|
||||
|
||||
MESH_VER = "0.8.5"
|
||||
MESH_VER = "0.7.93"
|
||||
|
||||
# for the update script, bump when need to recreate venv or npm install
|
||||
PIP_VER = "15"
|
||||
@@ -34,8 +34,8 @@ DL_64 = f"https://github.com/wh1te909/rmmagent/releases/download/v{LATEST_AGENT_
|
||||
DL_32 = f"https://github.com/wh1te909/rmmagent/releases/download/v{LATEST_AGENT_VER}/winagent-v{LATEST_AGENT_VER}-x86.exe"
|
||||
|
||||
EXE_GEN_URLS = [
|
||||
"https://exe2.tacticalrmm.io/api/v1/exe",
|
||||
"https://exe.tacticalrmm.io/api/v1/exe",
|
||||
"https://exe2.tacticalrmm.io",
|
||||
"https://exe.tacticalrmm.io",
|
||||
]
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
||||
@@ -12,6 +12,7 @@ from .utils import (
|
||||
generate_winagent_exe,
|
||||
get_bit_days,
|
||||
reload_nats,
|
||||
run_nats_api_cmd,
|
||||
)
|
||||
|
||||
|
||||
@@ -74,6 +75,12 @@ class TestUtils(TestCase):
|
||||
|
||||
mock_subprocess.assert_called_once()
|
||||
|
||||
@patch("subprocess.run")
|
||||
def test_run_nats_api_cmd(self, mock_subprocess):
|
||||
ids = ["a", "b", "c"]
|
||||
_ = run_nats_api_cmd("monitor", ids)
|
||||
mock_subprocess.assert_called_once()
|
||||
|
||||
def test_bitdays_to_string(self):
|
||||
a = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||
all_days = [
|
||||
|
||||
@@ -4,6 +4,7 @@ import string
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import urllib.parse
|
||||
from typing import Union
|
||||
|
||||
import pytz
|
||||
@@ -19,6 +20,7 @@ from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
from agents.models import Agent
|
||||
from core.models import CodeSignToken
|
||||
|
||||
logger.configure(**settings.LOG_CONFIG)
|
||||
|
||||
@@ -50,12 +52,27 @@ def generate_winagent_exe(
|
||||
file_name: str,
|
||||
) -> Union[Response, FileResponse]:
|
||||
|
||||
from agents.tasks import _get_exegen_url
|
||||
|
||||
inno = (
|
||||
f"winagent-v{settings.LATEST_AGENT_VER}.exe"
|
||||
if arch == "64"
|
||||
else f"winagent-v{settings.LATEST_AGENT_VER}-x86.exe"
|
||||
)
|
||||
|
||||
try:
|
||||
codetoken = CodeSignToken.objects.first().token
|
||||
base_url = _get_exegen_url() + "/api/v1/winagents/?"
|
||||
params = {
|
||||
"version": settings.LATEST_AGENT_VER,
|
||||
"arch": arch,
|
||||
"token": codetoken,
|
||||
}
|
||||
dl_url = base_url + urllib.parse.urlencode(params)
|
||||
except:
|
||||
codetoken = ""
|
||||
dl_url = settings.DL_64 if arch == "64" else settings.DL_32
|
||||
|
||||
data = {
|
||||
"client": client,
|
||||
"site": site,
|
||||
@@ -66,8 +83,9 @@ def generate_winagent_exe(
|
||||
"goarch": "amd64" if arch == "64" else "386",
|
||||
"token": token,
|
||||
"inno": inno,
|
||||
"url": settings.DL_64 if arch == "64" else settings.DL_32,
|
||||
"url": dl_url,
|
||||
"api": api,
|
||||
"codesigntoken": codetoken,
|
||||
}
|
||||
headers = {"Content-type": "application/json"}
|
||||
|
||||
@@ -76,7 +94,7 @@ def generate_winagent_exe(
|
||||
for url in settings.EXE_GEN_URLS:
|
||||
try:
|
||||
r = requests.post(
|
||||
url,
|
||||
f"{url}/api/v1/exe",
|
||||
json=data,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
@@ -228,3 +246,20 @@ class KnoxAuthMiddlewareInstance:
|
||||
KnoxAuthMiddlewareStack = lambda inner: KnoxAuthMiddlewareInstance(
|
||||
AuthMiddlewareStack(inner)
|
||||
)
|
||||
|
||||
|
||||
def run_nats_api_cmd(mode: str, ids: list[str], timeout: int = 30) -> None:
|
||||
config = {
|
||||
"key": settings.SECRET_KEY,
|
||||
"natsurl": f"tls://{settings.ALLOWED_HOSTS[0]}:4222",
|
||||
"agents": ids,
|
||||
}
|
||||
with tempfile.NamedTemporaryFile() as fp:
|
||||
with open(fp.name, "w") as f:
|
||||
json.dump(config, f)
|
||||
|
||||
cmd = ["/usr/local/bin/nats-api", "-c", fp.name, "-m", mode]
|
||||
try:
|
||||
subprocess.run(cmd, capture_output=True, timeout=timeout)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
@@ -14,8 +14,29 @@ class TestWinUpdateViews(TacticalTestCase):
|
||||
self.authenticate()
|
||||
self.setup_coresettings()
|
||||
|
||||
def test_get_winupdates(self):
|
||||
@patch("agents.models.Agent.nats_cmd")
|
||||
def test_run_update_scan(self, nats_cmd):
|
||||
agent = baker.make_recipe("agents.agent")
|
||||
url = f"/winupdate/{agent.pk}/runupdatescan/"
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
nats_cmd.assert_called_with({"func": "getwinupdates"}, wait=False)
|
||||
|
||||
self.check_not_authenticated("get", url)
|
||||
|
||||
@patch("agents.models.Agent.nats_cmd")
|
||||
def test_install_updates(self, nats_cmd):
|
||||
agent = baker.make_recipe("agents.agent")
|
||||
baker.make("winupdate.WinUpdate", agent=agent, _quantity=4)
|
||||
baker.make("winupdate.WinUpdatePolicy", agent=agent)
|
||||
url = f"/winupdate/{agent.pk}/installnow/"
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
nats_cmd.assert_called_once()
|
||||
|
||||
self.check_not_authenticated("get", url)
|
||||
|
||||
def test_get_winupdates(self):
|
||||
agent = baker.make_recipe("agents.agent")
|
||||
baker.make("winupdate.WinUpdate", agent=agent, _quantity=4)
|
||||
|
||||
@@ -27,8 +48,8 @@ class TestWinUpdateViews(TacticalTestCase):
|
||||
resp = self.client.get(url, format="json")
|
||||
serializer = UpdateSerializer(agent)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(len(resp.data["winupdates"]), 4)
|
||||
self.assertEqual(resp.data, serializer.data)
|
||||
self.assertEqual(len(resp.data["winupdates"]), 4) # type: ignore
|
||||
self.assertEqual(resp.data, serializer.data) # type: ignore
|
||||
|
||||
self.check_not_authenticated("get", url)
|
||||
|
||||
@@ -99,7 +120,7 @@ class TestWinUpdateViews(TacticalTestCase):
|
||||
resp = self.client.patch(url, invalid_data, format="json")
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
data = {"pk": winupdate.pk, "policy": "inherit"}
|
||||
data = {"pk": winupdate.pk, "policy": "inherit"} # type: ignore
|
||||
|
||||
resp = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import asyncio
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from packaging import version as pyver
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.response import Response
|
||||
|
||||
from agents.models import Agent
|
||||
from tacticalrmm.utils import get_default_timezone, notify_error
|
||||
from tacticalrmm.utils import get_default_timezone
|
||||
|
||||
from .models import WinUpdate
|
||||
from .serializers import UpdateSerializer
|
||||
@@ -24,9 +23,6 @@ def get_win_updates(request, pk):
|
||||
def run_update_scan(request, pk):
|
||||
agent = get_object_or_404(Agent, pk=pk)
|
||||
agent.delete_superseded_updates()
|
||||
if pyver.parse(agent.version) < pyver.parse("1.3.0"):
|
||||
return notify_error("Requires agent version 1.3.0 or greater")
|
||||
|
||||
asyncio.run(agent.nats_cmd({"func": "getwinupdates"}, wait=False))
|
||||
return Response("ok")
|
||||
|
||||
@@ -35,9 +31,6 @@ def run_update_scan(request, pk):
|
||||
def install_updates(request, pk):
|
||||
agent = get_object_or_404(Agent, pk=pk)
|
||||
agent.delete_superseded_updates()
|
||||
if pyver.parse(agent.version) < pyver.parse("1.3.0"):
|
||||
return notify_error("Requires agent version 1.3.0 or greater")
|
||||
|
||||
agent.approve_updates()
|
||||
nats_data = {
|
||||
"func": "installwinupdates",
|
||||
|
||||
@@ -19,7 +19,7 @@ Login to your Github
|
||||
|
||||
Choose local folder
|
||||
|
||||
### 3a. Install extra vscode Extensions
|
||||
#### 3a. Install extra vscode Extensions
|
||||
|
||||
GitLens
|
||||
|
||||
|
||||
2
scripts/Win_ADDC_Sync_Start.bat
Normal file
2
scripts/Win_ADDC_Sync_Start.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
net start ADSync
|
||||
exit
|
||||
15
scripts/Win_AzureAD_Check_Connection_Status.ps1
Normal file
15
scripts/Win_AzureAD_Check_Connection_Status.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
$ErrorActionPreference = 'silentlycontinue'
|
||||
$aadchk = dsregcmd /status | Where-Object { $_ -match 'AzureAdJoined : ' } | ForEach-Object { $_.Trim() }
|
||||
|
||||
if ($aadchk -Eq 'AzureAdJoined : Yes') {
|
||||
Write-Output "Machine is Azure Ad Joined"
|
||||
exit 0
|
||||
}
|
||||
|
||||
else {
|
||||
Write-Output "Machine is not Azure Ad Joined"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
23
scripts/Win_Azure_Mars_Cloud_Backup_Status.ps1
Normal file
23
scripts/Win_Azure_Mars_Cloud_Backup_Status.ps1
Normal file
@@ -0,0 +1,23 @@
|
||||
$ErrorActionPreference= 'silentlycontinue'
|
||||
$TimeSpan = (Get-Date) - (New-TimeSpan -Day 1)
|
||||
|
||||
##Check for Errors in Backup
|
||||
if (Get-WinEvent -FilterHashtable @{LogName='CloudBackup/Operational';ID='11','18';StartTime=$TimeSpan})
|
||||
|
||||
{
|
||||
Write-Host "Cloud Backup Mars Ended with Errors"
|
||||
Get-WinEvent -FilterHashtable @{LogName='CloudBackup/Operational';ID='1','14','11','18','16';StartTime=$TimeSpan}
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
|
||||
{
|
||||
Write-Host "Cloud Backup Mars Backup Is Working Correctly"
|
||||
Get-WinEvent -FilterHashtable @{LogName='CloudBackup/Operational';ID='1','14','16'}
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
1
scripts/Win_Bitlocker_Get_Recovery_Keys.ps1
Normal file
1
scripts/Win_Bitlocker_Get_Recovery_Keys.ps1
Normal file
@@ -0,0 +1 @@
|
||||
manage-bde -protectors C: -get
|
||||
1
scripts/Win_Disable_AutoRun.bat
Normal file
1
scripts/Win_Disable_AutoRun.bat
Normal file
@@ -0,0 +1 @@
|
||||
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" /v NoDriveTypeAutoRun /t REG_DWORD /d 255 /f
|
||||
1
scripts/Win_Disable_Cortana.bat
Normal file
1
scripts/Win_Disable_Cortana.bat
Normal file
@@ -0,0 +1 @@
|
||||
reg add "hklm\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /d "AllowCortana"=dword:00000000
|
||||
@@ -1,20 +1,18 @@
|
||||
# Checks local disks for errors reported in event viewer within the last 24 hours
|
||||
|
||||
$ErrorActionPreference= 'silentlycontinue'
|
||||
$ErrorActionPreference = 'silentlycontinue'
|
||||
$TimeSpan = (Get-Date) - (New-TimeSpan -Day 1)
|
||||
if (Get-WinEvent -FilterHashtable @{LogName='system';ID='11','9','15','52','129','7','98';Level=2,3;ProviderName='*disk*','*storsvc*','*ntfs*';StartTime=$TimeSpan})
|
||||
|
||||
if (Get-WinEvent -FilterHashtable @{LogName = 'system'; ID = '11', '9', '15', '52', '129', '7', '98'; Level = 2, 3; ProviderName = '*disk*', '*storsvc*', '*ntfs*'; StartTime = $TimeSpan } -MaxEvents 10 | Where-Object -Property Message -Match Volume*)
|
||||
{
|
||||
Write-Output "Disk errors detected please investigate"
|
||||
Get-WinEvent -FilterHashtable @{LogName='system';ID='11','9','15','52','129','7','98';Level=2,3;ProviderName='*disk*','*storsvc*','*ntfs*';StartTime=$TimeSpan}
|
||||
exit 1
|
||||
Write-Output "Disk errors detected please investigate"
|
||||
Get-WinEvent -FilterHashtable @{LogName = 'system'; ID = '11', '9', '15', '52', '129', '7', '98'; Level = 2, 3; ProviderName = '*disk*', '*storsvc*', '*ntfs*'; StartTime = $TimeSpan }
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
Write-Output "Disks are Healthy"
|
||||
exit 0
|
||||
else {
|
||||
Write-Output "Disks are Healthy"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
1
scripts/Win_FileSystem_Enable_Long_Paths.bat
Normal file
1
scripts/Win_FileSystem_Enable_Long_Paths.bat
Normal file
@@ -0,0 +1 @@
|
||||
REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /V LongPathsEnabled /T REG_DWORD /D 1 /F
|
||||
@@ -1 +1,5 @@
|
||||
Restart-Computer -ComputerName $env:COMPUTERNAME -Force
|
||||
# This script will force the computer to finish installing updates
|
||||
# and restart. Normal restart doesn't install updates before issuing
|
||||
# a reboot command. This one does.
|
||||
|
||||
Restart-Computer -ComputerName $env:COMPUTERNAME -Force
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
# This script will force the computer to finish installing updates
|
||||
# and shutdown. Normal shutdown doesn't install updates before issuing
|
||||
# a shutdown command. This one does.
|
||||
|
||||
Stop-Computer -ComputerName $env:COMPUTERNAME -Force
|
||||
17
scripts/Win_Firewall_Check_Status.ps1
Normal file
17
scripts/Win_Firewall_Check_Status.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
$ErrorActionPreference = 'silentlycontinue'
|
||||
$fwenabled = (get-netfirewallprofile -policystore activestore).Enabled
|
||||
|
||||
if ($fwenabled.Contains('True')) {
|
||||
Write-Output "Firewall is Enabled"
|
||||
netsh advfirewall show currentprofile
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
else {
|
||||
Write-Host "Firewall is Disabled"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
5
scripts/Win_Get_Computer_Users.ps1
Normal file
5
scripts/Win_Get_Computer_Users.ps1
Normal file
@@ -0,0 +1,5 @@
|
||||
# This script return the list of all users and checks
|
||||
# if they are enabled or disabled
|
||||
|
||||
get-localuser | Select name,Enabled > $env:TEMP\users.txt
|
||||
Get-Content $env:TEMP\users.txt | foreach {Write-Output $_}
|
||||
154
scripts/Win_Hardware_Monitor_Get_Info.ps1
Normal file
154
scripts/Win_Hardware_Monitor_Get_Info.ps1
Normal file
@@ -0,0 +1,154 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This powershell function gets information about the monitors attached to any computer. It uses EDID information provided by WMI. If this value is not specified it pulls the monitors of the computer that the script is being run on.
|
||||
.DESCRIPTION
|
||||
The function begins by looping through each computer specified. For each computer it gets a litst of monitors.
|
||||
It then gets all of the necessary data from each monitor object and converts and cleans the data and places it in a custom PSObject. It then adds
|
||||
the data to an array. At the end the array is displayed.
|
||||
.PARAMETER ComputerName
|
||||
Use this to specify the computer(s) which you'd like to retrieve information about monitors from.
|
||||
.EXAMPLE
|
||||
PS C:/> Get-Monitor.ps1 -ComputerName SSL1-F1102-1G2Z
|
||||
Manufacturer Model SerialNumber AttachedComputer
|
||||
------------ ----- ------------ ----------------
|
||||
HP HP E241i CN12345678 SSL1-F1102-1G2Z
|
||||
HP HP E241i CN91234567 SSL1-F1102-1G2Z
|
||||
HP HP E241i CN89123456 SSL1-F1102-1G2Z
|
||||
.EXAMPLE
|
||||
PS C:/> $Computers = @("SSL7-F108F-9D4Z","SSL1-F1102-1G2Z","SSA7-F1071-0T7F")
|
||||
PS C:/> Get-Monitor.ps1 -ComputerName $Computers
|
||||
Manufacturer Model SerialNumber AttachedComputer
|
||||
------------ ----- ------------ ----------------
|
||||
HP HP LA2405x CN12345678 SSL7-F108F-9D4Z
|
||||
HP HP E241i CN91234567 SSL1-F1102-1G2Z
|
||||
HP HP E241i CN89123456 SSL1-F1102-1G2Z
|
||||
HP HP E241i CN78912345 SSL1-F1102-1G2Z
|
||||
HP HP ZR22w CN67891234 SSA7-F1071-0T7F
|
||||
#>
|
||||
|
||||
|
||||
[CmdletBinding()]
|
||||
PARAM (
|
||||
[Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
|
||||
[String[]]$ComputerName = $env:ComputerName
|
||||
)
|
||||
|
||||
#List of Manufacture Codes that could be pulled from WMI and their respective full names. Used for translating later down.
|
||||
$ManufacturerHash = @{
|
||||
"AAC" = "AcerView";
|
||||
"ACR" = "Acer";
|
||||
"AOC" = "AOC";
|
||||
"AIC" = "AG Neovo";
|
||||
"APP" = "Apple Computer";
|
||||
"AST" = "AST Research";
|
||||
"AUO" = "Asus";
|
||||
"BNQ" = "BenQ";
|
||||
"CMO" = "Acer";
|
||||
"CPL" = "Compal";
|
||||
"CPQ" = "Compaq";
|
||||
"CPT" = "Chunghwa Pciture Tubes, Ltd.";
|
||||
"CTX" = "CTX";
|
||||
"DEC" = "DEC";
|
||||
"DEL" = "Dell";
|
||||
"DPC" = "Delta";
|
||||
"DWE" = "Daewoo";
|
||||
"EIZ" = "EIZO";
|
||||
"ELS" = "ELSA";
|
||||
"ENC" = "EIZO";
|
||||
"EPI" = "Envision";
|
||||
"FCM" = "Funai";
|
||||
"FUJ" = "Fujitsu";
|
||||
"FUS" = "Fujitsu-Siemens";
|
||||
"GSM" = "LG Electronics";
|
||||
"GWY" = "Gateway 2000";
|
||||
"HEI" = "Hyundai";
|
||||
"HIT" = "Hyundai";
|
||||
"HSL" = "Hansol";
|
||||
"HTC" = "Hitachi/Nissei";
|
||||
"HWP" = "HP";
|
||||
"IBM" = "IBM";
|
||||
"ICL" = "Fujitsu ICL";
|
||||
"IVM" = "Iiyama";
|
||||
"KDS" = "Korea Data Systems";
|
||||
"LEN" = "Lenovo";
|
||||
"LGD" = "Asus";
|
||||
"LPL" = "Fujitsu";
|
||||
"MAX" = "Belinea";
|
||||
"MEI" = "Panasonic";
|
||||
"MEL" = "Mitsubishi Electronics";
|
||||
"MS_" = "Panasonic";
|
||||
"NAN" = "Nanao";
|
||||
"NEC" = "NEC";
|
||||
"NOK" = "Nokia Data";
|
||||
"NVD" = "Fujitsu";
|
||||
"OPT" = "Optoma";
|
||||
"PHL" = "Philips";
|
||||
"REL" = "Relisys";
|
||||
"SAN" = "Samsung";
|
||||
"SAM" = "Samsung";
|
||||
"SBI" = "Smarttech";
|
||||
"SGI" = "SGI";
|
||||
"SNY" = "Sony";
|
||||
"SRC" = "Shamrock";
|
||||
"SUN" = "Sun Microsystems";
|
||||
"SEC" = "Hewlett-Packard";
|
||||
"TAT" = "Tatung";
|
||||
"TOS" = "Toshiba";
|
||||
"TSB" = "Toshiba";
|
||||
"VSC" = "ViewSonic";
|
||||
"ZCM" = "Zenith";
|
||||
"UNK" = "Unknown";
|
||||
"_YV" = "Fujitsu";
|
||||
}
|
||||
|
||||
|
||||
#Takes each computer specified and runs the following code:
|
||||
ForEach ($Computer in $ComputerName) {
|
||||
|
||||
#Grabs the Monitor objects from WMI
|
||||
$Monitors = Get-WmiObject -Namespace "root\WMI" -Class "WMIMonitorID" -ComputerName $Computer -ErrorAction SilentlyContinue
|
||||
|
||||
#Creates an empty array to hold the data
|
||||
$Monitor_Array = @()
|
||||
|
||||
|
||||
#Takes each monitor object found and runs the following code:
|
||||
ForEach ($Monitor in $Monitors) {
|
||||
|
||||
#Grabs respective data and converts it from ASCII encoding and removes any trailing ASCII null values
|
||||
If ([System.Text.Encoding]::ASCII.GetString($Monitor.UserFriendlyName) -ne $null) {
|
||||
$Mon_Model = ([System.Text.Encoding]::ASCII.GetString($Monitor.UserFriendlyName)).Replace("$([char]0x0000)", "")
|
||||
}
|
||||
else {
|
||||
$Mon_Model = $null
|
||||
}
|
||||
$Mon_Serial_Number = ([System.Text.Encoding]::ASCII.GetString($Monitor.SerialNumberID)).Replace("$([char]0x0000)", "")
|
||||
$Mon_Attached_Computer = ($Monitor.PSComputerName).Replace("$([char]0x0000)", "")
|
||||
$Mon_Manufacturer = ([System.Text.Encoding]::ASCII.GetString($Monitor.ManufacturerName)).Replace("$([char]0x0000)", "")
|
||||
|
||||
#Filters out "non monitors". Place any of your own filters here. These two are all-in-one computers with built in displays. I don't need the info from these.
|
||||
If ($Mon_Model -like "*800 AIO*" -or $Mon_Model -like "*8300 AiO*") { Break }
|
||||
|
||||
#Sets a friendly name based on the hash table above. If no entry found sets it to the original 3 character code
|
||||
$Mon_Manufacturer_Friendly = $ManufacturerHash.$Mon_Manufacturer
|
||||
If ($Mon_Manufacturer_Friendly -eq $null) {
|
||||
$Mon_Manufacturer_Friendly = $Mon_Manufacturer
|
||||
}
|
||||
|
||||
#Creates a custom monitor object and fills it with 4 NoteProperty members and the respective data
|
||||
$Monitor_Obj = [PSCustomObject]@{
|
||||
Manufacturer = $Mon_Manufacturer_Friendly
|
||||
Model = $Mon_Model
|
||||
SerialNumber = $Mon_Serial_Number
|
||||
AttachedComputer = $Mon_Attached_Computer
|
||||
}
|
||||
|
||||
#Appends the object to the array
|
||||
$Monitor_Array += $Monitor_Obj
|
||||
|
||||
} #End ForEach Monitor
|
||||
|
||||
#Outputs the Array
|
||||
$Monitor_Array
|
||||
|
||||
} #End ForEach Computer
|
||||
26
scripts/Win_Hardware_RAM_Status.ps1
Normal file
26
scripts/Win_Hardware_RAM_Status.ps1
Normal file
@@ -0,0 +1,26 @@
|
||||
#Identifies Computer RAM capacity and status
|
||||
|
||||
[Cmdletbinding()]
|
||||
Param(
|
||||
[string]$Computername = "localhost"
|
||||
)
|
||||
cls
|
||||
$PysicalMemory = Get-WmiObject -class "win32_physicalmemory" -namespace "root\CIMV2" -ComputerName $Computername
|
||||
|
||||
Write-Host "RAM Modules:" -ForegroundColor Green
|
||||
$PysicalMemory | Format-Table Tag, BankLabel, @{n = "Capacity(GB)"; e = { $_.Capacity / 1GB } }, Manufacturer, PartNumber, Speed -AutoSize
|
||||
|
||||
Write-Host "Total Memory:" -ForegroundColor Green
|
||||
Write-Host "$((($PysicalMemory).Capacity | Measure-Object -Sum).Sum/1GB)GB"
|
||||
|
||||
$TotalSlots = ((Get-WmiObject -Class "win32_PhysicalMemoryArray" -namespace "root\CIMV2" -ComputerName $Computername).MemoryDevices | Measure-Object -Sum).Sum
|
||||
Write-Host "`nTotal Memory Slots:" -ForegroundColor Green
|
||||
Write-Host $TotalSlots
|
||||
|
||||
$UsedSlots = (($PysicalMemory) | Measure-Object).Count
|
||||
Write-Host "`nUsed Memory Slots:" -ForegroundColor Green
|
||||
Write-Host $UsedSlots
|
||||
|
||||
If ($UsedSlots -eq $TotalSlots) {
|
||||
Write-Host "All memory slots are filled up, none is empty!" -ForegroundColor Yellow
|
||||
}
|
||||
17
scripts/Win_Local_User_Created_Monitor.ps1
Normal file
17
scripts/Win_Local_User_Created_Monitor.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
$ErrorActionPreference= 'silentlycontinue'
|
||||
$TimeSpan = (Get-Date) - (New-TimeSpan -Day 1)
|
||||
if (Get-WinEvent -FilterHashtable @{LogName='security';ID='4720','4720','4728','4732','4756','4767';StartTime=$TimeSpan})
|
||||
{
|
||||
Write-Output "A change has been made to local users"
|
||||
Get-WinEvent -FilterHashtable @{LogName='security';ID='4720','4720','4728','4732','4756','4767';StartTime=$TimeSpan}
|
||||
exit 1
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Write-Output "No changes all looks fine"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
1
scripts/Win_Power_Disable_Hibernation.bat
Normal file
1
scripts/Win_Power_Disable_Hibernation.bat
Normal file
@@ -0,0 +1 @@
|
||||
%SYSTEMROOT%\System32\powercfg.exe -H OFF
|
||||
1
scripts/Win_RecycleBin_Empty.ps1
Normal file
1
scripts/Win_RecycleBin_Empty.ps1
Normal file
@@ -0,0 +1 @@
|
||||
Clear-RecycleBin -Force
|
||||
3
scripts/Win_Set_Network_To_Private.ps1
Normal file
3
scripts/Win_Set_Network_To_Private.ps1
Normal file
@@ -0,0 +1,3 @@
|
||||
#This script sets current network profile to Private
|
||||
|
||||
$net = get-netconnectionprofile;Set-NetConnectionProfile -Name $net.Name -NetworkCategory Private
|
||||
1
scripts/Win_TRMM_Start_Menu_Delete_Shortcut.ps1
Normal file
1
scripts/Win_TRMM_Start_Menu_Delete_Shortcut.ps1
Normal file
@@ -0,0 +1 @@
|
||||
Remove-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Tactical RMM Agent.lnk" -Force
|
||||
6
scripts/Win_TaskScheduler_Add_Task.ps1
Normal file
6
scripts/Win_TaskScheduler_Add_Task.ps1
Normal file
@@ -0,0 +1,6 @@
|
||||
# Add a task to Task Scheduler
|
||||
|
||||
$Trigger = New-ScheduledTaskTrigger -At 10:00am –Daily # Specify the trigger settings
|
||||
$User = "NT AUTHORITY\SYSTEM" # Specify the account to run the script
|
||||
$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "YOUR COMMAND HERE" # Specify what program to run and with its parameters
|
||||
Register-ScheduledTask -TaskName "SomeTaskName" -Trigger $Trigger -User $User -Action $Action -RunLevel Highest –Force # Specify the name of the task
|
||||
18
scripts/Win_Task_Scheduler_New_Items_Monitor.ps1
Normal file
18
scripts/Win_Task_Scheduler_New_Items_Monitor.ps1
Normal file
@@ -0,0 +1,18 @@
|
||||
$ErrorActionPreference= 'silentlycontinue'
|
||||
$TimeSpan = (Get-Date) - (New-TimeSpan -Day 1)
|
||||
if (Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-TaskScheduler/Operational';ID='106';StartTime=$TimeSpan} | Where-Object -Property Message -notlike *$env:COMPUTERNAME*)
|
||||
{
|
||||
Write-Output "New Task Has Been Added"
|
||||
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-TaskScheduler/Operational';ID='106';StartTime=$TimeSpan}
|
||||
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-TaskScheduler/Operational';ID='141';StartTime=$TimeSpan}
|
||||
exit 1
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Write-Output "No changes with Task Scheduler"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
22
scripts/Win_UAC_Check_Status.ps1
Normal file
22
scripts/Win_UAC_Check_Status.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
$ErrorActionPreference = 'silentlycontinue'
|
||||
$PSDenabled = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).PromptOnSecureDesktop
|
||||
$CPAenabled = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).ConsentPromptBehaviorAdmin
|
||||
|
||||
|
||||
if ($PSDenabled -Eq 1 -And $CPAenabled -Eq 5) {
|
||||
Write-Output "UAC is Enabled"
|
||||
exit 0
|
||||
}
|
||||
|
||||
elseif ($PSDenabled -Eq 1 -And $CPAenabled -Eq 2) {
|
||||
Write-Output "UAC is Enabled"
|
||||
exit 0
|
||||
}
|
||||
|
||||
else {
|
||||
Write-Output "UAC is Disabled"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
1
scripts/Win_USB_Disable_Access.bat
Normal file
1
scripts/Win_USB_Disable_Access.bat
Normal file
@@ -0,0 +1 @@
|
||||
reg add HKLM\SYSTEM\CurrentControlSet\Services\UsbStor /v "Start" /t REG_DWORD /d "4" /f
|
||||
1
scripts/Win_USB_Enable_Access.bat
Normal file
1
scripts/Win_USB_Enable_Access.bat
Normal file
@@ -0,0 +1 @@
|
||||
reg add HKLM\SYSTEM\CurrentControlSet\Services\UsbStor /v "Start" /t REG_DWORD /d "3" /f
|
||||
17
scripts/Win_User_Logged_in_with_Temp_Profile.ps1
Normal file
17
scripts/Win_User_Logged_in_with_Temp_Profile.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
$ErrorActionPreference= 'silentlycontinue'
|
||||
$TimeSpan = (Get-Date) - (New-TimeSpan -Day 1)
|
||||
if (Get-WinEvent -FilterHashtable @{LogName='Application';ID='1511';StartTime=$TimeSpan})
|
||||
{
|
||||
Write-Output "An account has been logged in with a Temporary profile"
|
||||
Get-WinEvent -FilterHashtable @{LogName='Application';ID='1511';StartTime=$TimeSpan}
|
||||
exit 1
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Write-Output "All looks fine"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
Exit $LASTEXITCODE
|
||||
90
scripts/Win_WOL_Enable_Status.ps1
Normal file
90
scripts/Win_WOL_Enable_Status.ps1
Normal file
@@ -0,0 +1,90 @@
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
|
||||
begin {
|
||||
$PPNuGet = Get-PackageProvider -ListAvailable | Where-Object { $_.Name -eq 'Nuget' }
|
||||
if (!$PPNuget) {
|
||||
Write-Output 'Installing Nuget provider'
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
|
||||
}
|
||||
$PSGallery = Get-PSRepository -Name PsGallery
|
||||
if (!$PSGallery) {
|
||||
Write-Output 'Setting PSGallery as trusted Repository'
|
||||
Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
|
||||
}
|
||||
$PsGetVersion = (Get-Module PowerShellGet).version
|
||||
if ($PsGetVersion -lt [version]'2.0') {
|
||||
Write-Output 'Installing latest version of PowerShellGet provider'
|
||||
Install-Module PowerShellGet -MinimumVersion 2.2 -Force
|
||||
Write-Output 'Reloading Modules'
|
||||
Remove-Module PowerShellGet -Force
|
||||
Remove-Module PackageManagement -Force
|
||||
Import-Module PowerShellGet -MinimumVersion 2.2 -Force
|
||||
Write-Output 'Updating PowerShellGet'
|
||||
Install-Module -Name PowerShellGet -MinimumVersion 2.2.3 -Force
|
||||
Write-Output 'PowerShellGet update requires all active PS Sessions to be restarted before it can continue.'
|
||||
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
Write-Output 'Checking device Manufacturer'
|
||||
$Manufacturer = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer
|
||||
if ($Manufacturer -like '*Dell*') {
|
||||
Write-Output 'Manufacturer is Dell. Installing Module and trying to enable Wake on LAN.'
|
||||
Write-Output 'Installing Dell Bios Provider'
|
||||
Install-Module -Name DellBIOSProvider -Force
|
||||
Import-Module DellBIOSProvider
|
||||
try {
|
||||
Set-Item -Path 'DellSmBios:\PowerManagement\WakeOnLan' -Value 'LANOnly' -ErrorAction Stop
|
||||
}
|
||||
catch {
|
||||
Write-Output 'An error occured. Was unable to set WakeOnLan.'
|
||||
|
||||
Exit 2
|
||||
}
|
||||
}
|
||||
if ($Manufacturer -like '*HP*' -or $Manufacturer -like '*Hewlett*') {
|
||||
Write-Output 'Manufacturer is HP. Installing module and trying to enable WakeOnLan. All HP Drivers are required for this operation to succeed.'
|
||||
Write-Output 'Installing HP Provider'
|
||||
Install-Module -Name HPCMSL -Force -AcceptLicense
|
||||
Import-Module HPCMSL
|
||||
try {
|
||||
$WolTypes = get-hpbiossettingslist | Where-Object { $_.Name -like '*Wake On Lan*' }
|
||||
ForEach ($WolType in $WolTypes) {
|
||||
Write-Output "Setting WOL Type: $($WOLType.Name)"
|
||||
Set-HPBIOSSettingValue -name $($WolType.name) -Value 'Boot to Hard Drive' -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output 'An error occured. Was unable to set WakeOnLan.'
|
||||
|
||||
Exit 2
|
||||
}
|
||||
}
|
||||
if ($Manufacturer -like '*Lenovo*') {
|
||||
Write-Output 'Manufacturer is Lenovo. Trying to set via WMI. All Lenovo Drivers are required for this operation to succeed.'
|
||||
try {
|
||||
Write-Output 'Setting BIOS.'
|
||||
(Get-WmiObject -ErrorAction Stop -class 'Lenovo_SetBiosSetting' -namespace 'root\wmi').SetBiosSetting('WakeOnLAN,Primary') | Out-Null
|
||||
Write-Output 'Saving BIOS.'
|
||||
(Get-WmiObject -ErrorAction Stop -class 'Lenovo_SaveBiosSettings' -namespace 'root\wmi').SaveBiosSettings() | Out-Null
|
||||
}
|
||||
catch {
|
||||
Write-Output 'An error occured. Was unable to set WakeOnLan.'
|
||||
|
||||
Exit 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
Write-Output 'Setting NIC to enable WOL'
|
||||
$NicsWithWake = Get-CimInstance -ClassName 'MSPower_DeviceWakeEnable' -Namespace 'root/wmi'
|
||||
foreach ($Nic in $NicsWithWake) {
|
||||
Write-Output 'Enabling for NIC'
|
||||
Set-CimInstance $NIC -Property @{Enable = $true }
|
||||
}
|
||||
Exit 0
|
||||
}
|
||||
105
scripts/Win_WOL_Test_State.ps1
Normal file
105
scripts/Win_WOL_Test_State.ps1
Normal file
@@ -0,0 +1,105 @@
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
|
||||
begin {
|
||||
$PPNuGet = Get-PackageProvider -ListAvailable | Where-Object { $_.Name -eq 'Nuget' }
|
||||
if (!$PPNuget) {
|
||||
Write-Output 'Installing Nuget provider'
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
|
||||
}
|
||||
$PSGallery = Get-PSRepository -Name PsGallery
|
||||
if (!$PSGallery) {
|
||||
Write-Output 'Installing PSGallery'
|
||||
Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
|
||||
}
|
||||
$PsGetVersion = (Get-Module PowerShellGet).version
|
||||
if ($PsGetVersion -lt [version]'2.0') {
|
||||
Write-Output 'Installing latest version of PowerShellGet provider'
|
||||
Install-Module PowerShellGet -MinimumVersion 2.2 -Force
|
||||
Write-Output 'Reloading Modules'
|
||||
Remove-Module PowerShellGet -Force
|
||||
Remove-Module PackageManagement -Force
|
||||
Import-Module PowerShellGet -MinimumVersion 2.2 -Force
|
||||
Write-Output 'Updating PowerShellGet'
|
||||
Install-Module -Name PowerShellGet -MinimumVersion 2.2.3 -Force
|
||||
Write-Output 'PowerShellGet update requires all active PS Sessions to be restarted before it can continue.'
|
||||
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
Write-Output 'Checking Manufacturer'
|
||||
$Manufacturer = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer
|
||||
if ($Manufacturer -like '*Dell*') {
|
||||
Write-Output 'Manufacturer is Dell. Installing Module and trying to get WOL state'
|
||||
Write-Output 'Installing Dell Bios Provider if needed'
|
||||
$Mod = Get-Module DellBIOSProvider
|
||||
if (!$mod) {
|
||||
Install-Module -Name DellBIOSProvider -Force
|
||||
}
|
||||
Import-Module DellBIOSProvider
|
||||
try {
|
||||
$WOLMonitor = Get-Item -Path 'DellSmBios:\PowerManagement\WakeOnLan' -ErrorAction SilentlyContinue
|
||||
if ($WOLMonitor.currentvalue -eq 'LanOnly') { $WOLState = 'Healthy' }
|
||||
}
|
||||
catch {
|
||||
Write-Output 'An error occured. Could not get WOL setting.'
|
||||
|
||||
Exit 3
|
||||
}
|
||||
}
|
||||
if ($Manufacturer -like '*HP*' -or $Manufacturer -like '*Hewlett*') {
|
||||
Write-Output 'Manufacturer is HP. Installing module and trying to get WOL State.'
|
||||
Write-Output 'Installing HP Provider if needed.'
|
||||
$Mod = Get-Module HPCMSL
|
||||
if (!$mod) {
|
||||
Install-Module -Name HPCMSL -Force -AcceptLicense
|
||||
}
|
||||
Import-Module HPCMSL
|
||||
try {
|
||||
$WolTypes = get-hpbiossettingslist | Where-Object { $_.Name -like '*Wake On Lan*' }
|
||||
$WOLState = ForEach ($WolType in $WolTypes) {
|
||||
Write-Output "Setting WOL Type: $($WOLType.Name)"
|
||||
get-HPBIOSSettingValue -name $($WolType.name) -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Output 'An error occured. Could not find WOL state'
|
||||
|
||||
Exit 3
|
||||
}
|
||||
}
|
||||
if ($Manufacturer -like '*Lenovo*') {
|
||||
Write-Output 'Manufacturer is Lenovo. Trying to get via WMI'
|
||||
try {
|
||||
Write-Output 'Getting BIOS.'
|
||||
$currentSetting = (Get-WmiObject -ErrorAction Stop -class 'Lenovo_BiosSetting' -namespace 'root\wmi') | Where-Object { $_.CurrentSetting -ne '' }
|
||||
$WOLStatus = $currentSetting.currentsetting | ConvertFrom-Csv -Delimiter ',' -Header 'Setting', 'Status' | Where-Object { $_.setting -eq 'Wake on lan' }
|
||||
$WOLStatus = $WOLStatus.status -split ';'
|
||||
if ($WOLStatus[0] -eq 'Primary') { $WOLState = 'Healthy' }
|
||||
}
|
||||
catch {
|
||||
Write-Output 'An error occured. Could not find WOL state'
|
||||
|
||||
Exit 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
$NicsWithWake = Get-CimInstance -ClassName 'MSPower_DeviceWakeEnable' -Namespace 'root/wmi' | Where-Object { $_.Enable -eq $False }
|
||||
if (!$NicsWithWake) {
|
||||
$NICWOL = 'Healthy - All NICs enabled for WOL within the OS.'
|
||||
Exit 0
|
||||
}
|
||||
else {
|
||||
$NICWOL = 'Unhealthy - NIC does not have WOL enabled inside of the OS.'
|
||||
Exit 4
|
||||
}
|
||||
if (!$WOLState) {
|
||||
$NICWOL = 'Unhealthy - Could not find WOL state'
|
||||
Exit 3
|
||||
}
|
||||
return $NICWOL
|
||||
}
|
||||
48
scripts/Win_Win10_Change_Key_and_Activate.ps1
Normal file
48
scripts/Win_Win10_Change_Key_and_Activate.ps1
Normal file
@@ -0,0 +1,48 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
License Windows 10
|
||||
|
||||
.DESCRIPTION
|
||||
Insert License key into Windows 10 and activate
|
||||
|
||||
.NOTES
|
||||
For Windows installations in different languages, you will need to edit the following:
|
||||
Select-String -Pattern "^License Status:"
|
||||
and
|
||||
$LicenseStatus -match "Licensed"
|
||||
to match your specific language translation.
|
||||
|
||||
.FUNCTIONALITY
|
||||
PowerShell v3+
|
||||
#>
|
||||
|
||||
if ($Args.Count -eq 0) {
|
||||
Write-Output "New Product Key is Required"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$param1 = $args[0]
|
||||
|
||||
$OSKey = "$param1"
|
||||
$SLMgr = "C:\Windows\System32\slmgr.vbs"
|
||||
|
||||
Write-Output "Inserting license key: $OSKey"
|
||||
$InsertKey = & cscript $SLMgr /ipk $OSKey
|
||||
$RetryCount = 3
|
||||
|
||||
while ($RetryCount -gt 0) {
|
||||
Write-Output "Activating license key..."
|
||||
& cscript $SLMgr /ato
|
||||
|
||||
Write-Output "Verifying activation status"
|
||||
$SLMgrResult = & cscript $SLMgr /dli
|
||||
$LicenseStatus = ([string]($SLMgrResult | Select-String -Pattern "^License Status:")).Remove(0, 16)
|
||||
if ($LicenseStatus -match "Licensed") {
|
||||
Write-Host "Activation Successful" -ForegroundColor Green
|
||||
$retryCount = 0
|
||||
}
|
||||
else {
|
||||
Write-Error "Activation failed."
|
||||
$RetryCount -= 1
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,6 @@ module.exports = function () {
|
||||
],
|
||||
config: {
|
||||
loadingBar: {
|
||||
color: "red",
|
||||
size: "4px"
|
||||
},
|
||||
notify: {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<q-tab name="base_board" label="Motherboard" />
|
||||
<q-tab name="comp_sys_prod" label="Computer System Product" />
|
||||
<q-tab name="network_config" label="Network Config" />
|
||||
<q-tab name="graphics" label="Graphics" />
|
||||
<q-tab name="desktop_monitor" label="Monitors" />
|
||||
<q-tab name="network_adapter" label="Network Adapters" />
|
||||
</q-tabs>
|
||||
@@ -63,6 +64,9 @@
|
||||
<q-tab-panel name="desktop_monitor">
|
||||
<WmiDetail :info="desktop_monitor" />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="graphics">
|
||||
<WmiDetail :info="graphics" />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="network_adapter">
|
||||
<WmiDetail :info="network_adapter" />
|
||||
</q-tab-panel>
|
||||
@@ -125,6 +129,9 @@ export default {
|
||||
network_adapter() {
|
||||
return this.assets.network_adapter;
|
||||
},
|
||||
graphics() {
|
||||
return this.assets.graphics;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -89,6 +89,10 @@
|
||||
<q-item clickable v-close-popup @click="showEditCoreSettingsModal = true">
|
||||
<q-item-section>Global Settings</q-item-section>
|
||||
</q-item>
|
||||
<!-- code sign -->
|
||||
<q-item clickable v-close-popup @click="showCodeSign = true">
|
||||
<q-item-section>Code Signing</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
@@ -179,6 +183,10 @@
|
||||
<q-dialog v-model="showServerMaintenance">
|
||||
<ServerMaintenance @close="showMaintenance = false" />
|
||||
</q-dialog>
|
||||
<!-- Code Sign -->
|
||||
<q-dialog v-model="showCodeSign">
|
||||
<CodeSign @close="showCodeSign = false" />
|
||||
</q-dialog>
|
||||
</q-bar>
|
||||
</div>
|
||||
</template>
|
||||
@@ -201,6 +209,7 @@ import AuditManager from "@/components/AuditManager";
|
||||
import BulkAction from "@/components/modals/agents/BulkAction";
|
||||
import Deployment from "@/components/Deployment";
|
||||
import ServerMaintenance from "@/components/modals/core/ServerMaintenance";
|
||||
import CodeSign from "@/components/modals/coresettings/CodeSign";
|
||||
|
||||
export default {
|
||||
name: "FileBar",
|
||||
@@ -217,6 +226,7 @@ export default {
|
||||
BulkAction,
|
||||
Deployment,
|
||||
ServerMaintenance,
|
||||
CodeSign,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -233,6 +243,7 @@ export default {
|
||||
showDeployment: false,
|
||||
showDebugLog: false,
|
||||
showScriptManager: false,
|
||||
showCodeSign: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -39,6 +39,13 @@
|
||||
</q-item-section>
|
||||
<q-item-section>{{ disk }}</q-item-section>
|
||||
</q-item>
|
||||
<!-- graphics -->
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="fas fa-tv" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ summary.graphics }}</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="fas fa-globe-americas" />
|
||||
|
||||
67
web/src/components/modals/coresettings/CodeSign.vue
Normal file
67
web/src/components/modals/coresettings/CodeSign.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<q-card style="min-width: 85vh">
|
||||
<q-card-section class="row items-center">
|
||||
<div class="text-h6">Code Signing</div>
|
||||
<q-space />
|
||||
<q-btn icon="close" flat round dense v-close-popup />
|
||||
</q-card-section>
|
||||
<q-form @submit.prevent="editToken">
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Token:</div>
|
||||
<div class="col-1"></div>
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
v-model="settings.token"
|
||||
class="col-9 q-pa-none"
|
||||
:rules="[val => !!val || 'Token is required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row items-center">
|
||||
<q-btn label="Save" color="primary" type="submit" />
|
||||
</q-card-section>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
export default {
|
||||
name: "CodeSign",
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
settings: {
|
||||
token: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getToken() {
|
||||
this.$axios
|
||||
.get("/core/codesign/")
|
||||
.then(r => {
|
||||
this.settings = r.data;
|
||||
})
|
||||
.catch(e => this.notifyError(e.response.data));
|
||||
},
|
||||
editToken() {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.patch("/core/codesign/", this.settings)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
this.$emit("close");
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data, 4000);
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getToken();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -46,6 +46,18 @@
|
||||
class="col-4"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-4">Loading Bar Color:</div>
|
||||
<div class="col-4"></div>
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
options-dense
|
||||
v-model="loading_bar_color"
|
||||
:options="loadingBarColors"
|
||||
class="col-4"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Client Sort:</div>
|
||||
<div class="col-2"></div>
|
||||
@@ -73,6 +85,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { loadingBarColors } from "@/mixins/data";
|
||||
import mixins from "@/mixins/mixins";
|
||||
|
||||
export default {
|
||||
@@ -80,11 +93,13 @@ export default {
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
loadingBarColors,
|
||||
agentDblClickAction: "",
|
||||
defaultAgentTblTab: "",
|
||||
clientTreeSort: "",
|
||||
tab: "ui",
|
||||
splitterModel: 20,
|
||||
loading_bar_color: "",
|
||||
clientTreeSortOptions: [
|
||||
{
|
||||
label: "Sort alphabetically, moving failing clients to the top",
|
||||
@@ -131,6 +146,7 @@ export default {
|
||||
this.agentDblClickAction = r.data.dbl_click_action;
|
||||
this.defaultAgentTblTab = r.data.default_agent_tbl_tab;
|
||||
this.clientTreeSort = r.data.client_tree_sort;
|
||||
this.loading_bar_color = r.data.loading_bar_color;
|
||||
});
|
||||
},
|
||||
editUserPrefs() {
|
||||
@@ -138,6 +154,7 @@ export default {
|
||||
agent_dblclick_action: this.agentDblClickAction,
|
||||
default_agent_tbl_tab: this.defaultAgentTblTab,
|
||||
client_tree_sort: this.clientTreeSort,
|
||||
loading_bar_color: this.loading_bar_color,
|
||||
};
|
||||
this.$axios.patch("/accounts/users/ui/", data).then(r => {
|
||||
this.notifySuccess("Preferences were saved!");
|
||||
|
||||
@@ -20,21 +20,6 @@
|
||||
label="Select script"
|
||||
map-options
|
||||
emit-value
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-select
|
||||
dense
|
||||
label="Script Arguments (press Enter after typing each argument)"
|
||||
filled
|
||||
v-model="localTask.script_args"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
@input="setScriptDefaults"
|
||||
>
|
||||
<template v-slot:option="scope">
|
||||
<q-item v-if="!scope.opt.category" v-bind="scope.itemProps" v-on="scope.itemEvents" class="q-pl-lg">
|
||||
@@ -48,6 +33,21 @@
|
||||
</template>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-select
|
||||
dense
|
||||
label="Script Arguments (press Enter after typing each argument)"
|
||||
filled
|
||||
v-model="localTask.script_args"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
@input="setScriptDefaults"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
:rules="[val => !!val || '*Required']"
|
||||
@@ -55,6 +55,7 @@
|
||||
dense
|
||||
v-model="localTask.name"
|
||||
label="Descriptive name of task"
|
||||
class="q-pb-none"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -77,6 +78,7 @@
|
||||
v-model.number="localTask.timeout"
|
||||
type="number"
|
||||
label="Maximum permitted execution time (seconds)"
|
||||
class="q-pb-none"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
|
||||
@@ -59,4 +59,6 @@ const monthDays = [
|
||||
"31"
|
||||
]
|
||||
|
||||
export { scheduledTimes, monthDays };
|
||||
const loadingBarColors = ["red", "pink", "purple", "deep-purple", "indigo", "blue", "light-blue", "cyan", "teal", "green", "light-green", "lime", "yellow", "amber", "orange", "deep-orange", "brown", "grey", "blue-grey"]
|
||||
|
||||
export { scheduledTimes, monthDays, loadingBarColors };
|
||||
|
||||
@@ -33,8 +33,12 @@ export default function () {
|
||||
agentDblClickAction: "",
|
||||
defaultAgentTblTab: "server",
|
||||
clientTreeSort: "alphafail",
|
||||
clientTreeSplitter: 11,
|
||||
},
|
||||
getters: {
|
||||
clientTreeSplitterModel(state) {
|
||||
return state.clientTreeSplitter;
|
||||
},
|
||||
loggedIn(state) {
|
||||
return state.token !== null;
|
||||
},
|
||||
@@ -132,6 +136,9 @@ export default function () {
|
||||
agentHeight <= 15.0 ? state.tableHeight = "15vh" : state.tableHeight = `${agentHeight}vh`;
|
||||
tabsHeight <= 15.0 ? state.tabHeight = "15vh" : state.tabHeight = `${tabsHeight}vh`;
|
||||
},
|
||||
SET_CLIENT_SPLITTER(state, val) {
|
||||
state.clientTreeSplitter = val;
|
||||
},
|
||||
SET_NOTES(state, notes) {
|
||||
state.notes = notes;
|
||||
},
|
||||
@@ -149,6 +156,11 @@ export default function () {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setClientTreeSplitter(context, val) {
|
||||
axios.patch("/accounts/users/ui/", { client_tree_splitter: Math.trunc(val) }).then(r => {
|
||||
context.commit("SET_CLIENT_SPLITTER", val)
|
||||
})
|
||||
},
|
||||
setShowCommunityScripts(context, data) {
|
||||
axios.patch("/accounts/users/ui/", { show_community_scripts: data }).then(r => {
|
||||
context.commit("setShowCommunityScripts", data)
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
<q-page-container>
|
||||
<FileBar />
|
||||
<q-splitter v-model="outsideModel">
|
||||
<q-splitter v-model="clientTreeSplitter">
|
||||
<template v-slot:before>
|
||||
<div v-if="!treeReady" class="q-pa-sm q-gutter-sm text-center" style="height: 30vh">
|
||||
<q-spinner size="40px" color="primary" />
|
||||
@@ -397,7 +397,6 @@ export default {
|
||||
serverOfflineCount: 0,
|
||||
workstationCount: 0,
|
||||
workstationOfflineCount: 0,
|
||||
outsideModel: 11,
|
||||
selectedTree: "",
|
||||
innerModel: 50,
|
||||
clientActive: "",
|
||||
@@ -712,8 +711,10 @@ export default {
|
||||
getDashInfo(edited = true) {
|
||||
this.$store.dispatch("getDashInfo").then(r => {
|
||||
if (edited) {
|
||||
this.$q.loadingBar.setDefaults({ color: r.data.loading_bar_color });
|
||||
this.$store.commit("SET_DEFAULT_AGENT_TBL_TAB", r.data.default_agent_tbl_tab);
|
||||
this.$store.commit("SET_CLIENT_TREE_SORT", r.data.client_tree_sort);
|
||||
this.$store.commit("SET_CLIENT_SPLITTER", r.data.client_tree_splitter);
|
||||
}
|
||||
this.darkMode = r.data.dark_mode;
|
||||
this.$q.dark.set(this.darkMode);
|
||||
@@ -802,13 +803,21 @@ export default {
|
||||
treeReady: state => state.treeReady,
|
||||
clients: state => state.clients,
|
||||
}),
|
||||
...mapGetters(["selectedAgentPk", "needRefresh"]),
|
||||
...mapGetters(["selectedAgentPk", "needRefresh", "clientTreeSplitterModel"]),
|
||||
wsUrl() {
|
||||
return getBaseUrl().split("://")[1];
|
||||
},
|
||||
token() {
|
||||
return this.$store.state.token;
|
||||
},
|
||||
clientTreeSplitter: {
|
||||
get: function () {
|
||||
return this.clientTreeSplitterModel;
|
||||
},
|
||||
set: function (newVal) {
|
||||
this.$store.dispatch("setClientTreeSplitter", newVal);
|
||||
},
|
||||
},
|
||||
tab: {
|
||||
get: function () {
|
||||
return this.$store.state.defaultAgentTblTab;
|
||||
|
||||
@@ -72,10 +72,11 @@ export default {
|
||||
this.title = `${r.data.hostname} - ${r.data.client} - ${r.data.site} | Remote Background`;
|
||||
});
|
||||
},
|
||||
getDark() {
|
||||
getUI() {
|
||||
this.$store.dispatch("getDashInfo").then(r => {
|
||||
this.darkMode = r.data.dark_mode;
|
||||
this.$q.dark.set(this.darkMode);
|
||||
this.$q.loadingBar.setDefaults({ color: r.data.loading_bar_color });
|
||||
});
|
||||
},
|
||||
},
|
||||
@@ -90,7 +91,7 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getDark();
|
||||
this.getUI();
|
||||
this.genURLS();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -54,6 +54,12 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getUI() {
|
||||
this.$store.dispatch("getDashInfo").then(r => {
|
||||
this.$q.dark.set(r.data.dark_mode);
|
||||
this.$q.loadingBar.setDefaults({ color: r.data.loading_bar_color });
|
||||
});
|
||||
},
|
||||
genURL() {
|
||||
this.$q.loading.show();
|
||||
this.visible = false;
|
||||
@@ -117,6 +123,7 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getUI();
|
||||
this.genURL();
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user