Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28edc31d43 | ||
|
|
0f9872a818 | ||
|
|
76ce4296f3 | ||
|
|
3dd2671380 | ||
|
|
298ca31332 | ||
|
|
8f911aa6b9 | ||
|
|
82a5c7d9b1 | ||
|
|
7f013dcdba | ||
|
|
68e2e16076 | ||
|
|
ea23c763c9 | ||
|
|
5dcecb3206 | ||
|
|
5bd48e2d0e | ||
|
|
afd0a02589 | ||
|
|
2379192d53 | ||
|
|
a6489290c8 | ||
|
|
5f74c43415 |
@@ -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,6 @@
|
||||
import asyncio
|
||||
import datetime as dt
|
||||
import json
|
||||
import random
|
||||
import subprocess
|
||||
import tempfile
|
||||
from time import sleep
|
||||
from typing import Union
|
||||
|
||||
@@ -17,6 +14,7 @@ from core.models import CoreSettings
|
||||
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)
|
||||
|
||||
@@ -257,30 +255,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 +269,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)
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -65,6 +65,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,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -397,5 +397,42 @@
|
||||
"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"
|
||||
}
|
||||
]
|
||||
@@ -15,14 +15,14 @@ EXE_DIR = os.path.join(BASE_DIR, "tacticalrmm/private/exe")
|
||||
AUTH_USER_MODEL = "accounts.User"
|
||||
|
||||
# latest release
|
||||
TRMM_VERSION = "0.5.2"
|
||||
TRMM_VERSION = "0.5.3"
|
||||
|
||||
# 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.128"
|
||||
|
||||
# https://github.com/wh1te909/rmmagent
|
||||
LATEST_AGENT_VER = "1.4.13"
|
||||
LATEST_AGENT_VER = "1.4.14"
|
||||
|
||||
MESH_VER = "0.7.93"
|
||||
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -228,3 +228,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",
|
||||
|
||||
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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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