mirror of
https://gitlab.com/JKANetwork/powerfulcomputermanager.git
synced 2026-02-15 09:41:30 +01:00
First commit, only with CLI tools
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
**/thumbs.bd
|
||||
*.bak
|
||||
api.log
|
||||
client/config.ps1
|
||||
BD/database*
|
||||
reports/
|
||||
__pycache__/
|
||||
.vscode/
|
||||
cooks/*.yaml
|
||||
BIN
BD/emptydatabase.db
Normal file
BIN
BD/emptydatabase.db
Normal file
Binary file not shown.
51
README.MD
Normal file
51
README.MD
Normal file
@@ -0,0 +1,51 @@
|
||||
# What is "Powerful Computer Manager"?
|
||||
Powerful Computer Manager is the super-simple-but-powerful program to automatizate tasks in groups of computers (In a Active Directory site, or not) in a unattended way.
|
||||
It inteed to be a simple SSMS alternative, that inventarizes computers and install/remove software in it, tweak system of run arbitrary commands.
|
||||
|
||||
You only have to write simple _cooks_ that are small yaml text files, create groups of computers and assign _cooks_ to this computers, and will be run in the destination computers
|
||||
|
||||
|
||||
# Disclaimer
|
||||
|
||||
I'm using this program in the company I work with 10 computers with Windows 8.1/10 with various software (MSI,EXE,...) and tweaking services, and it works right
|
||||
|
||||
It's not super-stable and error proof, then, I don't have any responsability if something crashes, but you can open a Issue and will see it
|
||||
|
||||
# Roadmap
|
||||
|
||||
GUI administration in Python to superseed Powershell CLI control program and be cross-platform
|
||||
|
||||
# Requirements
|
||||
|
||||
## Server
|
||||
For server you can use Linux or Windows, and in theory any environment that can run Python 3 can work as server
|
||||
- Python3 with:
|
||||
- Falcon
|
||||
- Waitress-serve
|
||||
- Json (Python3 have it preinstalled)
|
||||
- Yaml
|
||||
Python3 deps can be installed it using pip install command (pip install waitress falcon pyyaml)
|
||||
- For controlling the program, you have to use "control.ps1" using Powershell. Powershell comes with Windows, and can be installed (PWCore) in Linux and macOS (I didn't tested it).
|
||||
|
||||
## Clients
|
||||
- Windows:
|
||||
- Windows 7 SP1 absolute minimal, but its only officially tested in 8.1 and 10, Windows 7 is being old now.
|
||||
- It needs Powershell 5.0+, lower versions doesn't have some commands, not tested. In Windows 7 and 8.1, you have to update Powershell. (With Powershell 3.0/4.0, some commands like Get-Package doesn't work)
|
||||
You can update from here: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell
|
||||
|
||||
- Linux:
|
||||
- Not supported yet, but when Windows be stable, I will try to do it in some way
|
||||
|
||||
|
||||
# Instalation. Example installing Server and using a GPO of Active Directory/Task Schedule to make it work in clients
|
||||
- Copy this folder to a folder in your server
|
||||
- Install dependencies
|
||||
- Open sysopt.py file and change values if needed
|
||||
- Use bat file if you are in Windows to run the python server, or sh file if you are in Linux environment
|
||||
- Go to Client folder and copy "configexample.ps1" to "config.ps1" and change their values to yours.
|
||||
- For clients to work, they have to run "client\client.ps1" every 30 mins/1 hour or so, I did using Active Directory and a Task Scheduled GPO (Copying client.ps1 and config.ps1 files from Client to SysVol\DomainName\Scripts\)
|
||||
- User: SYSTEM (Or NT\SYSTEM)
|
||||
- Command: powershell.exe
|
||||
- Args: -executionpolicy bypass -windowstyle hidden -noninteractive -nologo -file "\\SERVER\SysVol\DOMAINNAME\scripts\client.ps1"
|
||||
Note: client.ps1 has to have control.ps1 file with it
|
||||
- If you don't have Active Directory, you can do the Task Scheduled task in every computer without problems, and using another Shared folder, it will work
|
||||
541
api.py
Normal file
541
api.py
Normal file
@@ -0,0 +1,541 @@
|
||||
#!/usr/bin/python3
|
||||
# Build 5
|
||||
##It can be run directly with "waitress-serve --port=3333 api:api"
|
||||
import falcon
|
||||
import random
|
||||
import os
|
||||
import time
|
||||
import sql # SQL work file
|
||||
import json,yaml
|
||||
from datetime import datetime
|
||||
|
||||
import sysopt #File of options
|
||||
|
||||
def logit(text):
|
||||
text = str(text)
|
||||
now = datetime.now()
|
||||
print ("Log: " + text)
|
||||
with open('api.log', 'a') as file:
|
||||
file.write("Log ("+now.strftime("%x %X") + "): ")
|
||||
file.write(text)
|
||||
file.write('\n')
|
||||
|
||||
class getComputerExists(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerName,UUID = None, None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerName = value
|
||||
if key == "UUID":
|
||||
UUID = value
|
||||
|
||||
if ComputerName is None:
|
||||
response.media = {'RESULT': '0'}
|
||||
else:
|
||||
result = sql.select("SELECT COUNT(*) 'RESULT' FROM COMPUTERS WHERE Name='"+ComputerName+"' AND UUID='"+UUID+"'")
|
||||
|
||||
if result[0]['RESULT'] == 0: # 0 or 1
|
||||
if sql.select("SELECT COUNT(*) 'RESULT' FROM COMPUTERS WHERE Name='"+ComputerName+"' AND UUID IS NULL")[0]['RESULT'] != 0:
|
||||
sql.insert("UPDATE COMPUTERS SET UUID='"+UUID+"' WHERE Name='"+ComputerName+"'")
|
||||
response.media = {'RESULT': '1'}
|
||||
return
|
||||
if sysopt.addComputers == True:
|
||||
sql.insert("INSERT INTO COMPUTERS (`Name`,`UUID`) VALUES('"+ComputerName+"','"+UUID+"')")
|
||||
response.media = {'RESULT': '1'}
|
||||
else:
|
||||
response.media = {'RESULT': '0'}
|
||||
else: #Exists
|
||||
response.media = {'RESULT': '1'}
|
||||
|
||||
class getGroups(object): #Get local groups of a Computer
|
||||
def on_get(self,request, response):
|
||||
logit(request)
|
||||
ComputerID=None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
|
||||
if ComputerID is None:
|
||||
data = sql.select("SELECT * FROM GROUPS")
|
||||
response.media = data
|
||||
else:
|
||||
data = sql.select("SELECT * FROM GROUPS WHERE (SELECT ID_G FROM COMPUTER_GROUP WHERE ID_C = '"+ComputerID+"')")
|
||||
response.media = data
|
||||
|
||||
class getComputers(object):
|
||||
def on_get(self,request, response):
|
||||
logit(request)
|
||||
ComputerID=None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
|
||||
if ComputerID is None:
|
||||
data = sql.select("SELECT * FROM COMPUTERS")
|
||||
response.media = data
|
||||
else:
|
||||
data = sql.select("SELECT * FROM COMPUTERS WHERE ID_C = '"+ComputerID+"')")
|
||||
response.media = data
|
||||
|
||||
class getComputersGrp(object): #List of computers in a group
|
||||
def on_get(self,request, response):
|
||||
logit(request)
|
||||
GroupID=None
|
||||
for key, value in request.params.items():
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
data = sql.select("SELECT * FROM COMPUTERS WHERE ID_C IN (SELECT ID_C FROM COMPUTER_GROUP WHERE ID_G='"+GroupID+"') ORDER BY Name")
|
||||
response.media = data
|
||||
|
||||
class getCook(object): # Get the list of cooks for a computer to implement (Var all=1 for see all of, implemented or not)
|
||||
def on_get(self,request, response):
|
||||
logit(request)
|
||||
ComputerID,GroupID, SeeAll =None, None, None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
if key == "SeeAll":
|
||||
SeeAll = str(value)
|
||||
|
||||
if ComputerID is None and GroupID is None:
|
||||
response.media = {'ERROR': 'I need a Group or Computer to search'}
|
||||
elif ComputerID is not None and SeeAll is None:
|
||||
data = sql.select("SELECT * FROM COOKS_IDG WHERE ID_G IN (SELECT ID_G FROM COMPUTER_GROUP WHERE ID_C = '"+ComputerID+"')") #All cooks for this computer
|
||||
fordelete = []
|
||||
for i in range(len(data)):
|
||||
for key, value in data[i].items(): #Iterate in a dict (json)
|
||||
if key == 'CookName':
|
||||
CookName = value #Name
|
||||
with open('cooks/'+CookName+'.yaml', 'r') as myfile:
|
||||
filecook = myfile.read()
|
||||
coun = sql.select("SELECT COUNT(*) 'RESULT' FROM COOKS_STATUS WHERE ID_C='"+ComputerID+"' AND CookName='"+CookName+"' AND Revision='"+str(yaml.safe_load(filecook)['revision'])+"' AND `Error`='0'")
|
||||
if coun[0]['RESULT'] == 1:
|
||||
fordelete.append(i) #Its good, do not say to client
|
||||
for x in reversed(fordelete): #Deleting cooks that are implemented in client. Reverse order (Because is an array and index..)
|
||||
data.pop(x)
|
||||
response.media = data
|
||||
else:
|
||||
response.media = sql.select("SELECT * FROM COOKS_IDG WHERE ID_G IN (SELECT ID_G FROM COMPUTER_GROUP WHERE ID_C = '"+ComputerID+"')") #All cooks for this computer
|
||||
|
||||
|
||||
class setCook(object): #Assign Cook to group
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
GroupID, CookName = None, None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
exists = os.path.isfile('cooks/'+value+'.yaml')
|
||||
CookName = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
if GroupID is None or exists is False:
|
||||
response.media = {'ERROR': 'GroupID is not defined or Cook not exists'}
|
||||
elif int(sql.select("SELECT COUNT(*) 'COUNT' FROM COOKS_IDG WHERE `ID_G`='"+GroupID+"' AND `CookName`='"+CookName+"'")[0]['COUNT']) > 0:
|
||||
response.media = {'WARNING': 'This union GROUP-CookName exists'}
|
||||
else:
|
||||
result = sql.insert("INSERT INTO COOKS_IDG (`ID_G`,`CookName`) VALUES ('"+GroupID+"','"+CookName+"')")
|
||||
response.media = result
|
||||
|
||||
class delCookGrp(object): #Delete cook from a group
|
||||
def on_get(self,request,response):
|
||||
logit(request)
|
||||
GroupID, CookName = None, None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
exists = os.path.isfile('cooks/'+value+'.yaml')
|
||||
if exists:
|
||||
CookName = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
|
||||
if GroupID is not None and CookName is not None:
|
||||
result = sql.insert("DELETE FROM COOKS_IDG WHERE ID_G='"+GroupID+"' AND CookName='"+CookName+"'")
|
||||
response.media = result
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, no Group, or CookName does\'t exists'}
|
||||
|
||||
class delEmptyPcsGroup(object): #Delete all computers from a group
|
||||
def on_get(self,request,response):
|
||||
logit(request)
|
||||
GroupID = None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
|
||||
if GroupID is not None:
|
||||
result = sql.insert("DELETE FROM COMPUTER_GROUP WHERE ID_G='"+GroupID+"'")
|
||||
response.media = result
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, this group doesn\'t exists'}
|
||||
|
||||
|
||||
|
||||
class getCookGrp(object): # Get cooks from a Group
|
||||
def on_get(self,request,response):
|
||||
logit(request)
|
||||
GroupID = None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
|
||||
if GroupID is not None:
|
||||
result = sql.select("SELECT * FROM COOKS_IDG WHERE ID_G='"+GroupID+"'")
|
||||
response.media = result
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, no Group selected'}
|
||||
|
||||
class getGrpCook(object): # Get Groups of a Cook
|
||||
def on_get(self,request,response):
|
||||
logit(request)
|
||||
CookName = None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
exists = os.path.isfile('cooks/'+value+'.yaml')
|
||||
if exists:
|
||||
CookName = value
|
||||
|
||||
if CookName is not None:
|
||||
response.media = sql.select("SELECT Name FROM GROUPS WHERE ID_G IN (SELECT ID_G FROM COOKS_IDG WHERE CookName='"+CookName+"')")
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, no Cook selected'}
|
||||
|
||||
class getStatusCook(object): # Get Status of a Cook (If Brief=1 is sent too, brief status (Completed:X, updated:X..))
|
||||
def on_get(self,request,response):
|
||||
logit(request)
|
||||
CookName = None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
exists = os.path.isfile('cooks/'+value+'.yaml')
|
||||
if exists:
|
||||
CookName = value
|
||||
|
||||
if CookName is not None:
|
||||
response.media = sql.select("SELECT Name, Revision, Error FROM COMPUTERS,COOKS_STATUS WHERE CookName = '"+CookName+"' AND COMPUTERS.ID_C=COOKS_STATUS.ID_C")
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, no Cook selected'}
|
||||
|
||||
class getLastRevisionCook(object): # Get Number Revision (Revision=X)
|
||||
def on_get(self,request,response):
|
||||
logit(request)
|
||||
CookName = None # Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
exists = os.path.isfile('cooks/'+value+'.yaml')
|
||||
if exists:
|
||||
CookName = value
|
||||
|
||||
if CookName is not None:
|
||||
with open('cooks/'+CookName+'.yaml', 'r') as myfile:
|
||||
filecook = myfile.read()
|
||||
response.media = {'Revision': str(yaml.safe_load(filecook)['revision'])}
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, no Cook selected'}
|
||||
|
||||
class addComputer(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerName = None
|
||||
for key,value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerName = value
|
||||
|
||||
if ComputerName is None:
|
||||
response.media = {'RESULT': 'Error, you need a ComputerName to add'}
|
||||
else:
|
||||
result = sql.insert("INSERT INTO COMPUTERS (Name) VALUES ('"+ComputerName+"')")
|
||||
response.media = result
|
||||
|
||||
class addGroup(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
GroupName= None
|
||||
for key,value in request.params.items():
|
||||
if key == "GroupName":
|
||||
GroupName = value
|
||||
|
||||
|
||||
if GroupName is None:
|
||||
response.media = {'RESULT': 'Error, you need a GroupName to add'}
|
||||
else:
|
||||
result = sql.insert("INSERT INTO GROUPS (Name) VALUES ('"+GroupName+"')")
|
||||
response.media = result
|
||||
|
||||
class delGroup(object): #Delete group
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
GroupID= None
|
||||
for key,value in request.params.items():
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
|
||||
if GroupID is None:
|
||||
response.media = {'RESULT': 'Error, you need a GroupName to delete'}
|
||||
else:
|
||||
sql.insert("DELETE FROM COMPUTER_GROUP WHERE ID_G='"+GroupID+"'")
|
||||
sql.insert("DELETE FROM COOKS_IDG WHERE ID_G='"+GroupID+"'")
|
||||
result = sql.insert("DELETE FROM GROUPS WHERE ID_G='"+GroupID+"'")
|
||||
response.media = result
|
||||
|
||||
class updGroup(object): #Delete group
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
GroupID, GroupNewName= None, None
|
||||
for key,value in request.params.items():
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupNewName":
|
||||
Count = str(sql.select("SELECT COUNT(*) 'Count' FROM GROUPS WHERE Name='"+value+"'")[0]['Count'])
|
||||
if Count == "0":
|
||||
GroupNewName = value
|
||||
else:
|
||||
response.media = {'RESULT': 'Error, New group name exists'}
|
||||
|
||||
if GroupID is None or GroupNewName is None:
|
||||
response.media = {'RESULT': 'Error, you need a GroupName and new name to update name'}
|
||||
else:
|
||||
result = sql.insert("UPDATE GROUPS SET Name='"+GroupNewName+"' WHERE ID_G='"+GroupID+"'")
|
||||
response.media = result
|
||||
|
||||
class addGrpComputer(object): #Add computer to a group (Local)
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerID, GroupID= None, None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
|
||||
if ComputerID is None or GroupID is None:
|
||||
response.media = {'RESULT': 'Error, you need a Name and Group to add'}
|
||||
else:
|
||||
result = sql.insert("INSERT INTO COMPUTER_GROUP (ID_C,ID_G) VALUES ('"+ComputerID+"','"+GroupID+"')")
|
||||
response.media = result
|
||||
|
||||
class delGrpComputer(object): #Del computer from a group
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerID, GroupID= None, None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
if key == "GroupName":
|
||||
GroupID = str(sql.select("SELECT ID_G FROM GROUPS WHERE Name='"+value+"'")[0]['ID_G'])
|
||||
if key == "GroupID":
|
||||
GroupID = value
|
||||
|
||||
if ComputerID is None or GroupID is None:
|
||||
response.media = {'RESULT': 'Error, you need a Name and Group to add'}
|
||||
else:
|
||||
result = sql.insert("DELETE FROM COMPUTER_GROUP WHERE ID_C='"+ComputerID+"' AND ID_G='"+GroupID+"'")
|
||||
response.media = result
|
||||
|
||||
|
||||
class delComputer(object): #Delete computer
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerID= None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
|
||||
if ComputerID is None:
|
||||
response.media = {'RESULT': 'Error, you need a Name/ComputerID to update data'}
|
||||
else:
|
||||
sql.insert("DELETE FROM COMPUTER_GROUP WHERE ID_C='"+ComputerID+"'")
|
||||
sql.insert("DELETE FROM COOKS_STATUS WHERE ID_C='"+ComputerID+"'")
|
||||
resp = sql.insert("DELETE FROM COMPUTERS WHERE ID_C='"+ComputerID+"'")
|
||||
logit(resp)
|
||||
|
||||
|
||||
class updComputer(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerID, UUID= None, None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
try:
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
except:
|
||||
response.media = {'RESULT': 'Error: Computer not exists in database'}
|
||||
break
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
if key == "UUID":
|
||||
UUID = value
|
||||
if ComputerID is None and response.media is None:
|
||||
response.media = {'RESULT': 'Error, you need a ComputerName/ComputerID to update data'}
|
||||
elif response.media is None and ComputerID is not None and UUID is not None:
|
||||
Count = str(sql.select("SELECT COUNT(*) 'Count' FROM COMPUTERS WHERE UUID='"+UUID+"' AND ID_C='"+ComputerID+"'")[0]['Count'])
|
||||
if Count == "0":
|
||||
response.media = {'RESULT': 'Error, computer doesn\'t exists in database'}
|
||||
else:
|
||||
for key, value in request.params.items():
|
||||
if key == "SOVersion":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET SOVersion ='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
if key == "SOBit":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET SOBit ='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
if key == "SOCaption":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET SOCaption ='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
if key == "LastConnection":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET LastConnection ='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
if key == "LastUser":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET LastUser='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
if key == "RAM":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET RAM='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
if key == "CPUName":
|
||||
response.media = sql.insert("UPDATE COMPUTERS SET CPUName='"+value+"' WHERE ID_C='"+ComputerID+"'")
|
||||
|
||||
|
||||
class updCookName(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
CookName, CookNewName= None, None #Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
if os.path.isfile('cooks/'+value+'.yaml'):
|
||||
CookName= value
|
||||
else:
|
||||
response.media = {'RESULT': 'Error: Cook not exists in folder'}
|
||||
break
|
||||
if key == "CookNewName":
|
||||
if os.path.isfile('cooks/'+value+'.yaml'):
|
||||
response.media = {'RESULT': 'Error: There is a cook with the new name in folder!'}
|
||||
break
|
||||
else:
|
||||
CookNewName= value
|
||||
if CookName is None or CookNewName is None:
|
||||
response.media = {'RESULT': 'Error, you need the old and new Cook Name to update data'}
|
||||
elif response.media is None:
|
||||
old_file = os.path.join("cooks", CookName+'.yaml')
|
||||
new_file = os.path.join("cooks", CookNewName+'.yaml')
|
||||
os.rename(old_file, new_file)
|
||||
sql.insert("UPDATE COOKS_IDG SET CookName ='"+CookNewName+"' WHERE CookName='"+CookName+"'")
|
||||
response.media = sql.insert("UPDATE COOKS_STATUS SET CookName ='"+CookNewName+"' WHERE CookName='"+CookName+"'")
|
||||
|
||||
|
||||
class loadCook(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
CookName, ComputerID, UUID= None, None, None #Initialize
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
if os.path.isfile('cooks/'+value+'.yaml'):
|
||||
CookName= value
|
||||
else:
|
||||
response.media = {'RESULT': 'Error: Cook not exists in folder'}
|
||||
break
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
if key == "UUID":
|
||||
UUID = value
|
||||
|
||||
if CookName is None and response.media is None:
|
||||
response.media = {'RESULT': 'Error, you need a CookName to load it'}
|
||||
elif response.media is None:
|
||||
Count = str(sql.select("SELECT COUNT(*) 'Count' FROM COMPUTERS WHERE UUID='"+UUID+"' AND ID_C='"+ComputerID+"'")[0]['Count'])
|
||||
if Count == "0":
|
||||
response.media = {'RESULT': 'Error, computer doesn\'t exists in database'}
|
||||
else:
|
||||
with open('cooks/'+CookName+'.yaml', 'r') as myfile:
|
||||
data = myfile.read()
|
||||
response.media = yaml.safe_load(data)
|
||||
|
||||
class setCookStatus(object):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
CookName, ComputerID, Revision, Error,ErrorDesc= None, None, None, None, ""
|
||||
for key, value in request.params.items():
|
||||
if key == "CookName":
|
||||
if os.path.isfile('cooks/'+value+'.yaml'): # You have to know that cook exists.
|
||||
CookName= value
|
||||
else:
|
||||
response.media = {'RESULT': 'Error: Cook not exists in folder'}
|
||||
break
|
||||
if key == "ComputerName":
|
||||
ComputerID = str(sql.select("SELECT ID_C FROM COMPUTERS WHERE Name='"+value+"'")[0]['ID_C'])
|
||||
if key == "ComputerID":
|
||||
ComputerID = value
|
||||
if key == "Revision":
|
||||
Revision = value
|
||||
if key == "Error":
|
||||
Error = value
|
||||
if key == "ErrorDesc":
|
||||
ErrorDesc = value
|
||||
|
||||
if CookName is None and response.media is None:
|
||||
response.media = {'RESULT': 'Error, you need a CookName to load it'}
|
||||
elif response.media is None and CookName is not None and ComputerID is not None and Revision is not None and Error is not None:
|
||||
statt = sql.select("SELECT COUNT(*) 'RESULT' FROM COOKS_STATUS WHERE CookName='"+CookName+"' AND ID_C='"+ComputerID+"'")[0]['RESULT']
|
||||
if statt == 0:
|
||||
#INSERT, NEW
|
||||
response.media = sql.insert("INSERT INTO COOKS_STATUS (CookName,ID_C,Revision,`Error`,`ErrorDesc`) VALUES ('"+CookName+"', '"+ComputerID+"', '"+Revision+"','"+Error+"','"+ErrorDesc+"')")
|
||||
else:
|
||||
#UPDATE, NOT NEW
|
||||
response.media = sql.insert("UPDATE COOKS_STATUS SET Revision='"+Revision+"',`Error`='"+Error+"',`ErrorDesc`='"+ErrorDesc+"' WHERE ID_C='"+ComputerID+"' AND CookName='"+CookName+"'")
|
||||
else:
|
||||
response.media = {'RESULT': 'Error in parameters...'}
|
||||
|
||||
logit(response.media)
|
||||
|
||||
|
||||
api = falcon.API()
|
||||
api.add_route('/get/computers', getComputers()) #Get list of computer
|
||||
api.add_route('/get/computerexists', getComputerExists()) #Returns 0 or 1 (name status)
|
||||
api.add_route('/get/groups', getGroups()) #Get groups of a computer (Or list if not args)
|
||||
api.add_route('/get/computersgrp', getComputersGrp()) #Get computers in a group
|
||||
api.add_route('/get/cook', getCook()) #Get cooks from a group
|
||||
api.add_route('/set/cook', setCook()) #Assign cook to group
|
||||
api.add_route('/del/cookgrp', delCookGrp()) # Deassign cook from a group
|
||||
api.add_route('/del/emptypcsgroup', delEmptyPcsGroup()) # Delete all computers from a group
|
||||
api.add_route('/get/cookgrp', getCookGrp()) # See cooks that have a determinated group
|
||||
api.add_route('/get/grpcook', getGrpCook()) # See groups of a determinated cook
|
||||
api.add_route('/get/statuscook', getStatusCook()) # See status of a cook
|
||||
api.add_route('/get/lastrevisioncook', getLastRevisionCook()) # Returns number of last revision of a cook
|
||||
api.add_route('/add/computer', addComputer()) #Add computer
|
||||
api.add_route('/del/computer', delComputer()) #Delete computer
|
||||
api.add_route('/add/group', addGroup()) #Add group to the list of local groups
|
||||
api.add_route('/del/group', delGroup()) #Delete group
|
||||
api.add_route('/upd/group', updGroup()) #Update group name
|
||||
api.add_route('/add/grpcomputer', addGrpComputer()) #Add computer to a group
|
||||
api.add_route('/del/grpcomputer', delGrpComputer()) #Delete computer from a group
|
||||
|
||||
api.add_route('/upd/computer', updComputer()) #Update data of computer
|
||||
api.add_route('/upd/cookname', updCookName()) #Update file name of cook and SQL references to it.
|
||||
api.add_route('/load/cook', loadCook()) # Load a cook (Transfer in json way)
|
||||
api.add_route('/set/cookstatus', setCookStatus()) # Update status of a cook in a computer
|
||||
76
client/ADcomputerData.ps1
Normal file
76
client/ADcomputerData.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
$root = $PSCommandPath | Split-Path -Parent
|
||||
. $root\config.ps1
|
||||
|
||||
$table = (Invoke-RestMethod -Method Get -Uri "$server/get/computers") # Get all computers
|
||||
$DNSPrefix = (get-DnsClientGlobalSetting).SuffixSearchList[0] # Get DNS Prefix, needed to search computers in some environments
|
||||
|
||||
|
||||
$array = @()
|
||||
|
||||
function getPrograms($computername) {
|
||||
|
||||
|
||||
#Define the variable to hold the location of Currently Installed Programs
|
||||
|
||||
$UninstallKey="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
|
||||
|
||||
#Create an instance of the Registry Object and open the HKLM base key
|
||||
|
||||
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computername)
|
||||
|
||||
#Drill down into the Uninstall key using the OpenSubKey Method
|
||||
|
||||
$regkey=$reg.OpenSubKey($UninstallKey)
|
||||
|
||||
#Retrieve an array of string that contain all the subkey names
|
||||
|
||||
$subkeys=$regkey.GetSubKeyNames()
|
||||
|
||||
#Open each Subkey and use GetValue Method to return the required values for each
|
||||
|
||||
$allprogs = @()
|
||||
|
||||
foreach($key in $subkeys){
|
||||
|
||||
$thisKey=$UninstallKey+"\\"+$key
|
||||
|
||||
$thisSubKey=$reg.OpenSubKey($thisKey)
|
||||
|
||||
$obj = New-Object PSObject
|
||||
|
||||
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $computername
|
||||
|
||||
$obj | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $($thisSubKey.GetValue("DisplayName"))
|
||||
|
||||
$obj | Add-Member -MemberType NoteProperty -Name "DisplayVersion" -Value $($thisSubKey.GetValue("DisplayVersion"))
|
||||
|
||||
$obj | Add-Member -MemberType NoteProperty -Name "InstallLocation" -Value $($thisSubKey.GetValue("InstallLocation"))
|
||||
|
||||
$obj | Add-Member -MemberType NoteProperty -Name "Publisher" -Value $($thisSubKey.GetValue("Publisher"))
|
||||
|
||||
|
||||
$allprogs += $obj
|
||||
|
||||
}
|
||||
|
||||
return $allprogs
|
||||
}
|
||||
|
||||
|
||||
foreach ($comp in $table){
|
||||
$name = -join($comp.Name,".",$DNSPrefix);
|
||||
if (Test-Connection -ComputerName $name -Quiet){
|
||||
Write-Output $name
|
||||
$array += getPrograms($name)
|
||||
}else{
|
||||
Write-Output "$name Offline"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#$array | Where-Object { $_.DisplayName } | select ComputerName, DisplayName, DisplayVersion, Publisher | ft -auto
|
||||
|
||||
$array | Where-Object { $_.DisplayName } | select ComputerName, DisplayName, DisplayVersion | export-csv "$PSScriptRoot\..\Reports\software.csv" -NoTypeInformation -Delimiter ";" -Encoding ASCII
|
||||
Write-Host "Guardado en ..\Reports\software.csv"
|
||||
#$content = [System.IO.File]::ReadAllText("$PSScriptRoot\Reports\software.csv").Replace("A","")
|
||||
#[System.IO.File]::WriteAllText("$PSScriptRoot\Reports\software.csv", $content)
|
||||
310
client/PCM.fbp
Normal file
310
client/PCM.fbp
Normal file
@@ -0,0 +1,310 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration">; </property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file"></property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">0</property>
|
||||
<property name="name">MyProject1</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Frame" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">MainFrame</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">749,396</property>
|
||||
<property name="style">wxDEFAULT_FRAME_STYLE</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="title"></property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
<property name="xrc_skip_sizer">1</property>
|
||||
<object class="wxMenuBar" expanded="1">
|
||||
<property name="bg"></property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">MyMenuBar</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_menubar1</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<object class="wxMenu" expanded="1">
|
||||
<property name="label">Equipos</property>
|
||||
<property name="name">m_computers</property>
|
||||
<property name="permission">protected</property>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Añadir equipo</property>
|
||||
<property name="name">scomp_addc</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Borrar equipo</property>
|
||||
<property name="name">scomp_deletec</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="wxMenu" expanded="1">
|
||||
<property name="label">Grupos</property>
|
||||
<property name="name">m_groups</property>
|
||||
<property name="permission">protected</property>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Añadir Grupo</property>
|
||||
<property name="name">sgroup_addg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Borrar grupo</property>
|
||||
<property name="name">sgroup_delg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Ver equipos de un grupo</property>
|
||||
<property name="name">sgroup_seeg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Vaciar grupo</property>
|
||||
<property name="name">sgroup_emptyg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Cambiar nombre de un grupo</property>
|
||||
<property name="name">sgroup_reng</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Recetas asignadas a un grupo</property>
|
||||
<property name="name">sgroup_cooksg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="wxMenu" expanded="1">
|
||||
<property name="label">Recetas</property>
|
||||
<property name="name">m_cooks</property>
|
||||
<property name="permission">protected</property>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Recetas de un grupo</property>
|
||||
<property name="name">scook_cooksg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Añadir receta a un grupo</property>
|
||||
<property name="name">scook_addcookg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Borrar receta de un grupo</property>
|
||||
<property name="name">scook_deletecookg</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Renombrar receta</property>
|
||||
<property name="name">scook_renamecook</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Detalles de implantación de una receta</property>
|
||||
<property name="name">scook_detailscook</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="wxMenu" expanded="1">
|
||||
<property name="label">Reportes</property>
|
||||
<property name="name">m_reports</property>
|
||||
<property name="permission">protected</property>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Reporte de equipos</property>
|
||||
<property name="name">srep_rcomp</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Reporte de grupos</property>
|
||||
<property name="name">srep_rgroup</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
<object class="wxMenuItem" expanded="1">
|
||||
<property name="bitmap"></property>
|
||||
<property name="checked">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="help"></property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="kind">wxITEM_NORMAL</property>
|
||||
<property name="label">Reporte de recetas</property>
|
||||
<property name="name">srep_rcook</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="shortcut"></property>
|
||||
<property name="unchecked_bitmap"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
||||
218
client/client.ps1
Normal file
218
client/client.ps1
Normal file
@@ -0,0 +1,218 @@
|
||||
# Build 2
|
||||
$root = $PSCommandPath | Split-Path -Parent
|
||||
. $root\config.ps1
|
||||
|
||||
$computerName = $env:COMPUTERNAME
|
||||
$UUID=(get-wmiobject Win32_ComputerSystemProduct).UUID
|
||||
|
||||
$exists = Invoke-RestMethod -Method Get -Uri "$server/get/computerexists?ComputerName=$computerName&UUID=$UUID"
|
||||
if ($exists.Result -eq 0){
|
||||
Write-Host "Computer outside database:" $computerName
|
||||
exit
|
||||
}
|
||||
|
||||
$Timestamp = [int64](([datetime]::UtcNow)-(get-date "1/1/1970")).TotalSeconds
|
||||
# Hardware Data
|
||||
$SOData = Get-CimInstance Win32_OperatingSystem
|
||||
$SOVersion = $SOData.Version
|
||||
if ($SOVersion -match "^10.0."){ #If its Windows 10, add revision number for knowing hotfix installed
|
||||
$revi = -join(".",(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion' UBR).UBR)
|
||||
$SOVersion += $revi
|
||||
}
|
||||
|
||||
# Update Computer Data
|
||||
$CPUInfo = Get-WmiObject Win32_Processor
|
||||
$RAMInstalled = Get-WmiObject CIM_PhysicalMemory | Measure-Object -Property capacity -Sum | ForEach-Object {[math]::round(($_.sum / 1MB),2)}
|
||||
$paramInvoke = -join("$server/upd/computer?ComputerName=$computerName&UUID=",$UUID,"&SOVersion=",$SOVersion,"&SOCaption=",$SOData.Caption,"&SOBit=",$SOData.OsArchitecture.Substring(0,2),"&LastConnection=",$Timestamp,"&RAM=",$RAMInstalled,"&CPUName=",$CPUInfo.Name)
|
||||
Invoke-RestMethod -Method Get -Uri $paramInvoke | out-null
|
||||
# More info
|
||||
$lastUser = (Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName -ComputerName .).UserName
|
||||
Invoke-RestMethod -Method Get -Uri "$server/upd/computer?ComputerName=$computerName&UUID=$UUID&LastUser=$lastUser" | out-null
|
||||
|
||||
|
||||
$cooks = Invoke-RestMethod -Method Get -Uri "$server/get/cook?ComputerName=$computerName&UUID=$UUID"
|
||||
|
||||
foreach ($CookName in $cooks){
|
||||
Set-Location $env:temp # For downloading/copying items, use system temp location
|
||||
$CookName = $CookName.CookName
|
||||
$cook = Invoke-RestMethod -Method Get -Uri "$server/load/cook?CookName=$CookName&ComputerName=$computerName&UUID=$UUID"
|
||||
Write-Host "Receta:" $cook.name
|
||||
$CookRevision = $cook.revision
|
||||
$err = 0
|
||||
$exit = 0
|
||||
$inif = $false
|
||||
$if = $true
|
||||
$filesCopied = New-Object System.Collections.ArrayList # For REPOTOLOCAL, has a list of files copied to delete when finish (Do not store forever in temp)
|
||||
foreach ($step in $cook.steps){
|
||||
if ($err -eq 1 -and $noerror -eq 1){$err = 0; $errvar = ""} #If "noerror" is active, do not count errors
|
||||
if ($err -eq 1 -or $exit -eq 1){break} # Halt if err ocurred (And noerror directive is not active)
|
||||
$step = $step.Split("|")
|
||||
$param = $step[1]
|
||||
Write-Host $step[0] "-" $step[1]
|
||||
if($inif -eq $true -and $if -eq $false){ # Only can see "ENDIF" if is in IF and is not true
|
||||
if ($step[0] -ne "ENDIF" -and $step[0] -ne "ELSE"){
|
||||
Write-Host $step[0] "Not executed, IF not meet"
|
||||
$step[0] = "" #Disable command
|
||||
$step[1] = ""
|
||||
}
|
||||
}
|
||||
|
||||
switch ($step[0].ToUpper()) { #Command
|
||||
"UNINSTALL" { # Remove program
|
||||
Get-Package -Name "$param*" -ErrorAction Continue #This will return error if program is not installed, do not see it.
|
||||
if ($? -eq $true){ #If its True, is that package exists
|
||||
Get-Package -Name "$param*" -ErrorVariable errvar | Uninstall-Package -ErrorVariable errvar
|
||||
if ($? -eq $false){ # If fail then put 1 (When fail, powershell returns False)
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
"SERV_DISABLE" { # Disable a service
|
||||
Set-Service $param -StartupType Disabled -Status Stopped -ErrorVariable errvar
|
||||
if ($? -eq $false){ #If its False, it was a problem
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
"SERV_ENABLE" { # Enable a service
|
||||
Set-Service $param -StartupType Automatic -Status Running -ErrorVariable errvar
|
||||
if ($? -eq $false){ #If its False, it was a problem
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
"KILL_PROCESS" {
|
||||
$p = Get-Process -Name "$param"
|
||||
if ($? -eq $true){ # Only do something if exists
|
||||
Stop-Process -InputObject $p -Force -ErrorVariable errvar -ErrorAction Continue
|
||||
#if ($p.HasExited -eq $false){
|
||||
# $err = 1
|
||||
#}
|
||||
}
|
||||
}
|
||||
"CMD" { # Run a cmd command. Note: Runs at high priv.
|
||||
cmd.exe /c "$param"
|
||||
if ($? -eq $false){ # Error in CMD
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
"PWCMD" { # Run a powershell command. Note: Runs as high priv.
|
||||
Invoke-Expression $param
|
||||
if ($? -eq $false){ # Error in CMD
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
"REPOTOLOCAL" { # Copy file from repo location to local ($env:temp) for use in cmd or other things
|
||||
Copy-Item "$resources\$param" $env:temp -ErrorVariable errvar -Recurse -Force
|
||||
if ($? -eq $false){ # Error in Copy
|
||||
$err = 1
|
||||
}
|
||||
$filesCopied.Add($param) > $null #Add to list
|
||||
}
|
||||
"REMOVE" { # Remove files / folders
|
||||
Remove-Item "$param" -Recurse -Force -ErrorAction Continue # They not see errors (Because error will be file not found)
|
||||
}
|
||||
"INSTALLMSI" { # Installs a .msi file (From $env:temp)
|
||||
Start-Process msiexec.exe -Wait -ArgumentList "/norestart /quiet /I $param" -ErrorVariable errvar
|
||||
if ($? -eq $false){ # Error in MSI
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
"REGFILE" { # Imports a .reg file
|
||||
reg import .\$param
|
||||
if ($? -eq $false){ # Error importing reg file
|
||||
$err = 1
|
||||
}
|
||||
}
|
||||
"MSG" { # Display a message
|
||||
msg * "$param"
|
||||
}
|
||||
{$_ -in "SLEEP","PAUSE"}{ # Pause exec some seconds
|
||||
[int]$secs = $param
|
||||
Start-Sleep -Seconds $secs
|
||||
}
|
||||
"NOERROR" { #All within NOERROR doesn't generate errors and stop scripts
|
||||
$noerror = 1
|
||||
}
|
||||
"ENDNOERROR" {
|
||||
$noerror = 0
|
||||
}
|
||||
"IFSOFTWAREINST" { # If with software
|
||||
$inif = $true #This controls IF start/stop
|
||||
Get-Package -Name "$param*" -ErrorAction SilentlyContinue #This will return error if program is not installed, do not see it.
|
||||
$if=$? # True -> Exists ; False -> Not exists
|
||||
}
|
||||
"IFSOFTWAREVER" { # If with software
|
||||
$inif = $true #This controls IF start/stop
|
||||
$parts = $param.Split(";")
|
||||
if ($parts[1] -ne ""){ #Exists uri and filename
|
||||
$p_name = $parts[0]
|
||||
$p_ver = $parts[1]
|
||||
Get-Package -Name "$p_name*" -MinimumVersion "$p_ver" -MaximumVersion "$p_ver" -ErrorAction SilentlyContinue #This will return error if program is not installed, do not see it.
|
||||
$if=$? # True -> Exists ; False -> Not exists
|
||||
}else{ #Doesn't sent right
|
||||
$err = 1
|
||||
$errvar = "Param not set right. Exiting..."
|
||||
}
|
||||
}
|
||||
"IFPATHEXISTS" { # If only if a path exists (File, Folder, Registry Key..)
|
||||
$inif = $true #This controls IF start/stop
|
||||
Test-Path $param -PathType Any -ErrorAction SilentlyContinue
|
||||
$if=$?
|
||||
}
|
||||
"IFPWCMD" { # If with powershell command
|
||||
$inif = $true #This controls IF start/stop
|
||||
Invoke-Expression $param #Executes powershell command
|
||||
$if=$? # True -> Exists ; False -> Not exists
|
||||
}
|
||||
"ELSE" { # Turn bool $if
|
||||
$if = !$if
|
||||
}
|
||||
"ENDIF"{ # End the if
|
||||
$inif = $false
|
||||
$if = $true
|
||||
}
|
||||
"DOWNLOAD" { #Download a file. This is a bit problematic one, will use ; to separate download and filename, and its forced to use it..
|
||||
$parts = $param.Split(";")
|
||||
if ($parts[1] -ne ""){ #Exists uri and filename
|
||||
$progressPreference = 'silentlyContinue'
|
||||
Invoke-WebRequest -Uri $parts[0] -OutFile $parts[1] -UseBasicParsing -ErrorVariable errvar
|
||||
$progressPreference = 'Continue'
|
||||
$filesCopied.Add($parts[1]) > $null #Add to list
|
||||
}else{ #Doesn't sent right
|
||||
$err = 1
|
||||
$errvar = "Param not set right. Exiting..."
|
||||
}
|
||||
}
|
||||
"EXIT"{ # Exits cook completly. If some param, exit will be with "error"
|
||||
if ($param){ #Exit with error message
|
||||
$noerror = 0
|
||||
$err = 1
|
||||
$errvar = $param
|
||||
$exit = 1
|
||||
}else{ #Exit as sucessful
|
||||
$err = 0
|
||||
$errvar = ""
|
||||
$exit = 1
|
||||
}
|
||||
}
|
||||
Default {}
|
||||
}
|
||||
}
|
||||
# Send results
|
||||
if ($errvar){ #There is an error if this has something
|
||||
$errvar = $($errvar | Out-String)
|
||||
$errvar = [System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes($errvar))
|
||||
$err = 1
|
||||
}else{
|
||||
$errvar=""
|
||||
}
|
||||
if ($cook.runever -eq "1"){
|
||||
$err = -1 # This is for run but not for error, is by cook saw.
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$server/set/cookstatus?ComputerName=$computerName&UUID=$UUID&CookName=$CookName&Revision=$CookRevision&Error=$err&ErrorDesc=$errvar" | out-null
|
||||
|
||||
#Delete files copied to temp for saving space
|
||||
foreach ($element in $filesCopied) {
|
||||
Remove-Item "$env:temp\$element" -ErrorAction SilentlyContinue -Recurse -Force
|
||||
}
|
||||
|
||||
}
|
||||
2
client/configexample.ps1
Normal file
2
client/configexample.ps1
Normal file
@@ -0,0 +1,2 @@
|
||||
$server = "http://miserver.dominio:3333" #Server that runs api service
|
||||
$resources = "\\MISERVER\REPOFOLDER" #Where files for copy are (Not cooks)
|
||||
317
client/control.ps1
Normal file
317
client/control.ps1
Normal file
@@ -0,0 +1,317 @@
|
||||
# Build 1
|
||||
$root = $PSCommandPath | Split-Path -Parent
|
||||
. $root\config.ps1
|
||||
|
||||
function seeGroups {
|
||||
$answer = Invoke-RestMethod -Method Get -Uri "$server/get/groups"
|
||||
foreach ($st in $answer){
|
||||
Write-Host "Grupo:" $st.Name
|
||||
}
|
||||
}
|
||||
function seeComputers {
|
||||
$answer = Invoke-RestMethod -Method Get -Uri "$server/get/computers"
|
||||
foreach ($st in $answer){
|
||||
Write-Host "Ordenador:" $st.Name
|
||||
}
|
||||
}
|
||||
|
||||
function menuReportes {
|
||||
|
||||
do
|
||||
{
|
||||
Write-Host "================ Menu reportes ================"
|
||||
|
||||
|
||||
Write-Host "1) Reporte de Software"
|
||||
Write-Host "Q) Salir"
|
||||
$input = Read-Host "Elegir una Opcion"
|
||||
switch ($input)
|
||||
{
|
||||
'1' {
|
||||
Clear-Host
|
||||
. "$PSScriptRoot\ADcomputerData.ps1"
|
||||
pause
|
||||
} 'q' {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
until ($input -eq 'q')
|
||||
|
||||
|
||||
}
|
||||
|
||||
function menuEquipos {
|
||||
|
||||
do
|
||||
{
|
||||
Write-Host "================ Menu equipos ================"
|
||||
|
||||
|
||||
Write-Host "1) Reporte de Equipos en pantalla"
|
||||
Write-Host "2) Añadir equipo"
|
||||
Write-Host "3) Borrar equipo"
|
||||
Write-Host "4) Añadir equipo a un grupo"
|
||||
Write-Host "5) Borrar equipo de un grupo"
|
||||
Write-Host "Q) Salir"
|
||||
$input = Read-Host "Elegir una Opcion"
|
||||
switch ($input)
|
||||
{
|
||||
'1' {
|
||||
Clear-Host
|
||||
seeComputers #Function
|
||||
pause
|
||||
} '2' {
|
||||
Clear-Host
|
||||
$newHost = Read-Host -Prompt "Nombre del equipo"
|
||||
if (Test-Connection -ComputerName $newHost -Quiet){
|
||||
Write-Output "$newHost Online"
|
||||
Write-Output "Añadiendo equipo"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/add/computer?ComputerName=$newHost"
|
||||
}else{
|
||||
Write-Output "$newHost Offline"
|
||||
}
|
||||
pause
|
||||
|
||||
} '3' {
|
||||
Clear-Host
|
||||
$hhost = Read-Host -Prompt "Nombre del equipo a eliminar"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/del/computer?ComputerName=$hhost"
|
||||
} '4' {
|
||||
Clear-Host
|
||||
$computer = Read-Host -Prompt "Nombre del equipo"
|
||||
# See all groups
|
||||
seeGroups #Function
|
||||
$newGroup = Read-Host -Prompt "Nombre del grupo a añadir"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/add/grpcomputer?ComputerName=$computer&GroupName=$newGroup"
|
||||
pause
|
||||
} '5' {
|
||||
Clear-Host
|
||||
$computer = Read-Host -Prompt "Nombre del equipo"
|
||||
# See all groups
|
||||
seeGroups #Function
|
||||
$newGroup = Read-Host -Prompt "Nombre del grupo a quitar"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/add/grpcomputer?ComputerName=$computer&GroupName=$newGroup"
|
||||
pause
|
||||
} 'q' {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
until ($input -eq 'q')
|
||||
|
||||
|
||||
}
|
||||
|
||||
function menuGrupos {
|
||||
|
||||
do
|
||||
{
|
||||
Write-Host "================ Menu grupos ================"
|
||||
|
||||
|
||||
Write-Host "1) Reporte de Grupos en pantalla"
|
||||
Write-Host "2) Ver equipos de un grupo"
|
||||
Write-Host "3) Añadir grupo"
|
||||
Write-Host "4) Borrar grupo"
|
||||
Write-Host "5) Vaciar equipos del grupo"
|
||||
Write-Host "6) Cambiar nombre del grupo"
|
||||
Write-Host "7) Ver recetas de un grupo"
|
||||
Write-Host "Q) Salir"
|
||||
$input = Read-Host "Elegir una Opción"
|
||||
switch ($input)
|
||||
{
|
||||
'1' {
|
||||
Clear-Host
|
||||
seeGroups #Function
|
||||
pause
|
||||
} '2' {
|
||||
Clear-Host
|
||||
seeGroups
|
||||
$GroupName = Read-Host -Prompt "Nombre del grupo a ver"
|
||||
if ($GroupName){
|
||||
$answer = Invoke-RestMethod -Method Get -Uri "$server/get/computersgrp?GroupName=$GroupName"
|
||||
foreach ($st in $answer){
|
||||
Write-Host "Ordenador:" $st.Name
|
||||
}
|
||||
}
|
||||
pause
|
||||
} '3' {
|
||||
Clear-Host
|
||||
$newGroup = Read-Host -Prompt "Nombre del grupo a añadir"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/add/group?GroupName=$newGroup"
|
||||
pause
|
||||
|
||||
} '4' {
|
||||
Clear-Host
|
||||
seeGroups #Function
|
||||
$grpName = Read-Host -Prompt "Nombre del grupo a eliminar"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/del/group?GroupName=$grpName"
|
||||
} '5' {
|
||||
Clear-Host
|
||||
seeGroups #Function
|
||||
$grpName = Read-Host -Prompt "Nombre del grupo a quitar los equipos"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/del/emptypcsgroup?GroupName=$grpName"
|
||||
} '6' {
|
||||
Clear-Host
|
||||
# See all groups
|
||||
seeGroups #Function
|
||||
$GroupName = Read-Host -Prompt "Nombre del grupo"
|
||||
$GroupNewName = Read-Host -Prompt "Nombre nuevo"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/upd/group?GroupName=$GroupName&GroupNewName=$GroupNewName"
|
||||
pause
|
||||
} '7' {
|
||||
Clear-Host
|
||||
# See all groups
|
||||
seeGroups #Function
|
||||
$GroupName = Read-Host -Prompt "Nombre del grupo para ver recetas"
|
||||
if ($GroupName){
|
||||
$answer = Invoke-RestMethod -Method Get -Uri "$server/get/cookgrp?GroupName=$GroupName"
|
||||
foreach ($st in $answer){
|
||||
Write-Host "Receta:" $st.CookName
|
||||
}
|
||||
}else{
|
||||
Write-Host "No hay grupo"
|
||||
}
|
||||
pause
|
||||
} 'q' {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
until ($input -eq 'q')
|
||||
|
||||
}
|
||||
|
||||
|
||||
function menuCooks {
|
||||
|
||||
do
|
||||
{
|
||||
Write-Host "================ Menu recetas (Cooks) ================"
|
||||
|
||||
|
||||
Write-Host "1) Grupos de una receta"
|
||||
Write-Host "2) Estado de una receta"
|
||||
Write-Host "3) Detalles de cada equipo de una receta"
|
||||
Write-Host "4) Añadir receta a un grupo"
|
||||
Write-Host "5) Borrar receta de un grupo"
|
||||
Write-Host "6) Renombrar receta"
|
||||
Write-Host "Q) Salir"
|
||||
$input = Read-Host "Elegir una Opción"
|
||||
switch -regex ($input)
|
||||
{
|
||||
'1' {
|
||||
Clear-Host
|
||||
$CookName = Read-Host -Prompt "Nombre de la receta"
|
||||
Write-Host "Grupos de la receta $CookName"
|
||||
$grpcook = Invoke-RestMethod -Method Get -Uri "$server/get/grpcook?CookName=$CookName"
|
||||
foreach ($st in $grpcook){
|
||||
Write-Host "Grupo:" $st.Name
|
||||
}
|
||||
pause
|
||||
} '2|3' {
|
||||
Clear-Host
|
||||
$CookName = Read-Host -Prompt "Nombre de la receta"
|
||||
|
||||
Write-Host "Grupos de la receta"
|
||||
$grpcook = Invoke-RestMethod -Method Get -Uri "$server/get/grpcook?CookName=$CookName"
|
||||
foreach ($st in $grpcook){
|
||||
Write-Host "Grupo:" $st.Name
|
||||
}
|
||||
|
||||
$cookrevision = Invoke-RestMethod -Method Get -Uri "$server/get/lastrevisioncook?CookName=$CookName"
|
||||
$answer = Invoke-RestMethod -Method Get -Uri "$server/get/statuscook?CookName=$CookName"
|
||||
|
||||
if ($_ -eq '3'){
|
||||
foreach ($st in $answer){
|
||||
Write-Host "Ordenador:" $st.Name ", revision" $st.Revision ", error" $st.Error
|
||||
}
|
||||
Write-Host "------Resumen y errores------"
|
||||
}
|
||||
$estadistica = @{}
|
||||
$estadistica.Total = 0
|
||||
$estadistica.Error = 0
|
||||
$estadistica.NotLast = 0
|
||||
foreach ($st in $answer){
|
||||
$estadistica.Total++
|
||||
if ($st.Error -eq '1'){
|
||||
Write-Host "Ordenador en error:" $st.Name
|
||||
$estadistica.Error++
|
||||
}
|
||||
if ($st.Revision -ne $cookrevision.Revision){
|
||||
Write-Host "Ordenador sin la última revisión de la receta:" $st.Name
|
||||
$estadistica.NotLast++
|
||||
}
|
||||
}
|
||||
Write-Host "Total implementado:" $estadistica.Total
|
||||
Write-Host "Errores:" $estadistica.Error
|
||||
Write-Host "Sin aplicar ultima revisión:" $estadistica.NotLast
|
||||
pause
|
||||
} '4' {
|
||||
Clear-Host
|
||||
|
||||
$CookName = Read-Host -Prompt "Nombre de la receta a añadir"
|
||||
seeGroups #Function
|
||||
$GroupName = Read-Host -Prompt "Nombre del grupo que quieres que lo tenga"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/set/cook?GroupName=$GroupName&CookName=$CookName"
|
||||
pause
|
||||
|
||||
} '5' {
|
||||
Clear-Host
|
||||
$CookName = Read-Host -Prompt "Nombre del receta a eliminar de un grupo"
|
||||
$grpcook = Invoke-RestMethod -Method Get -Uri "$server/get/grpcook?CookName=$CookName"
|
||||
foreach ($st in $grpcook){
|
||||
Write-Host "Grupo:" $st.Name
|
||||
}
|
||||
$GroupName = Read-Host -Prompt "Nombre del grupo"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/del/cookgrp?GroupName=$GroupName&CookName=$CookName"
|
||||
pause
|
||||
} '6' {
|
||||
Clear-Host
|
||||
$CookName = Read-Host -Prompt "Nombre del receta actual"
|
||||
$CookNewName = Read-Host -Prompt "Nuevo nombre"
|
||||
Invoke-RestMethod -Method Get -Uri "$server/upd/cookname?CookNewName=$CookNewName&CookName=$CookName"
|
||||
pause
|
||||
} 'q' {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
until ($input -eq 'q')
|
||||
|
||||
}
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
Write-Host "================ Menú principal ================"
|
||||
|
||||
|
||||
Write-Host "1) Reportes"
|
||||
Write-Host "2) Equipos"
|
||||
Write-Host "3) Grupos (Locales)"
|
||||
Write-Host "4) Recetas"
|
||||
Write-Host "Q) Salir"
|
||||
$input = Read-Host "Elegir una Opción"
|
||||
switch ($input)
|
||||
{
|
||||
'1' {
|
||||
Clear-Host
|
||||
menuReportes
|
||||
} '2' {
|
||||
Clear-Host
|
||||
menuEquipos
|
||||
} '3' {
|
||||
Clear-Host
|
||||
menuGrupos
|
||||
} '4' {
|
||||
Clear-Host
|
||||
menuCooks
|
||||
} 'q' {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
until ($input -eq 'q')
|
||||
1
cooks/README.MD
Normal file
1
cooks/README.MD
Normal file
@@ -0,0 +1 @@
|
||||
# Here you have to put cook files in .yaml
|
||||
5
doc/example_cooks/install_exefile.yaml
Normal file
5
doc/example_cooks/install_exefile.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
name: Install exe file, example with WinSCP
|
||||
revision: 1
|
||||
steps:
|
||||
- REPOTOLOCAL|WinSCP-5.13.4-Setup.exe
|
||||
- CMD|WinSCP-5.13.4-Setup.exe /VERYSILENT /NORESTART
|
||||
6
doc/example_cooks/install_msioptions.yaml
Normal file
6
doc/example_cooks/install_msioptions.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
name: Install MSI with options (Do not put standard silent options!)
|
||||
revision: 2
|
||||
steps:
|
||||
- REPOTOLOCAL|msiwithoptions.msi
|
||||
- INSTALLMSI|msiwithoptions.msi ADDLOCAL=Server SERVER_REGISTER_AS_SERVICE=1 SERVER_ADD_FIREWALL_EXCEPTION=1 SERVER_ALLOW_SAS=1
|
||||
- REMOVE|C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ProgramThatIDoNotWantUserToSee|Delete start menu folder
|
||||
5
doc/example_cooks/install_simplemsi.yaml
Normal file
5
doc/example_cooks/install_simplemsi.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
name: Install MSI File. By default, it is silent
|
||||
revision: 1
|
||||
steps:
|
||||
- REPOTOLOCAL|simplemsi.msi
|
||||
- INSTALLMSI|simplemsi.msi
|
||||
7
doc/example_cooks/remove_program.yaml
Normal file
7
doc/example_cooks/remove_program.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
name: Remove WinRar as Example
|
||||
revision: 4
|
||||
steps:
|
||||
- UNINSTALL|WinRAR|This uninstalls WinRAR from Control Panel directly (Powershell powered uninstall)
|
||||
- NOERROR|Do not fail if this fails
|
||||
- CMD|"C:\Program Files\WinRAR\Uninstall.exe" /S
|
||||
- ENDNOERROR|End of never exit if fail
|
||||
24
doc/file_hierarchy.md
Normal file
24
doc/file_hierarchy.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# File hierarchy
|
||||
|
||||
## Root folder
|
||||
- api.py -> Server file. It manages all requests from clients and connects to database
|
||||
- loadserver.bat -> A helper to run api.py on Windows
|
||||
- sql.py -> Helper for api.py sql sentences
|
||||
- sysopt.py -> Config of api and sql
|
||||
|
||||
## Client folder
|
||||
- client.ps1 -> This file has to run every X time (I suggest every hour) on every client and as NT\SYSTEM or local admin. You can do this with a Task Schedule as SYSTEM in a GPO (Active Directory)
|
||||
- control.ps1 -> This is the cli of the program. With that you manages the client-server program. It has to be in same folder as client.ps1 file
|
||||
|
||||
## BD folder
|
||||
- database.db -> Database file in sqlite3
|
||||
|
||||
## cooks folder
|
||||
It has the cooks in yaml format.
|
||||
Warning: Do not change name of cooks created and assigned directly.
|
||||
|
||||
## Doc folder
|
||||
Documentation...
|
||||
|
||||
## REPO folder (This isn't needeed to be there)
|
||||
You have to have this shared on LAN, this is the folder that cooks use to retrieve your files (As .exe/.msi) to use in scripts.
|
||||
13
doc/how_works.md
Normal file
13
doc/how_works.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Very-Fast instructions
|
||||
You have to create a cook
|
||||
In "Examples" you have Cook Examples
|
||||
|
||||
Then, you have to create a group using the CLI.
|
||||
In the groups is where you assign computers and cooks
|
||||
|
||||
Cooks -> Group
|
||||
Computers -> Group
|
||||
|
||||
You can have more than 1 cook in a group
|
||||
|
||||
You can call the groups equal to cooks and assign this cook to the group and you have a 1<->1
|
||||
48
doc/howto_writecook.md
Normal file
48
doc/howto_writecook.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# How to
|
||||
Cooks are in yaml format, and have this structure.
|
||||
|
||||
First: Name, a line like below, with the name
|
||||
"name: My Super Cook"
|
||||
Then, the revision number, when this number changes, cook will be reapplied
|
||||
"revision: 1"
|
||||
If the cook has to run everytime client is called (And not only one time per new revision), you have to add:
|
||||
"runever: 1" (1-> Everytime; 0 or no line: Run only one time)
|
||||
And then, steps. First a "steps:" line, and then line by line the steps of the cook
|
||||
"steps:
|
||||
- PWCMD|White-Output "Hello World"
|
||||
"
|
||||
Steps are ever put like "Type of step" | "Command"
|
||||
You can put comments in every line putting another "|" and comments at finish, like.. "CMD|WinSCP-5.13.4-Setup.exe /VERYSILENT /NORESTART|Note: Installing WinSCP"
|
||||
|
||||
Cook finishes executing if they had and error (Except in a NOERROR block), or if finishes right.
|
||||
|
||||
Note: Cooks start in directory $env:temp (%TEMP%) from SYSTEM user.
|
||||
|
||||
# Type of commands
|
||||
- CMD and PWCMD: cmd command or Powershell command. Cmd commands can not work properly if has quotes (Because its run as cmd /c ""), if they are a Powershell equivalent, please use it. Normally cmd command uses are for install/uninstall exe programs or some like that, because powershell doesn't wait to exit a exe command
|
||||
- REPOTOLOCAL: Copy a file from REPO folder configured to local in temp folder to use it. You can copy files or folders with same command.
|
||||
- INSTALLMSI: Installs an MSI file silently (Params /quiet /norestart are put, do not repeat). You can add parameters (Like INSTALLMSI|superapp.msi ADDLOCAL=extension SETASDEFAULT=1)
|
||||
- NOERROR and ENDNOERROR: This is for creating a block of instructions that not captures errors, then cook works ever if instruction fails
|
||||
Example:
|
||||
NOERROR|For deleting a file that maybe can not exist
|
||||
PWCMD|Remove-Item C:\Windows\loginstall.txt
|
||||
ENDNOERROR|Finish
|
||||
- SERV_DISABLE and SERV_ENABLE: Enables or disables a Windows Service
|
||||
- MSG|Display a message to user
|
||||
- COMMENT or REM: Makes cook comments (COMMENT|This is a comment)
|
||||
- KILL_PROCESS: Kill a process name if exists
|
||||
- UNINSTALL: Uninstalls a program by name if its installed. It searchs it by Powershell command 'Get-Package -Name "Program*"', take care of it. You can use to see name
|
||||
- REMOVE: Removes a file or folder path from local computer. It's recursive
|
||||
- SLEEP and PAUSE: Pauses execution seconds specified in param
|
||||
- DOWNLOAD: This downloads a file from network/internet to $env:temp/filename. Its *required* to put a filename, that goes this way: DOWNLOAD|http://www.example.org/file.zip;filename.zip. ";" is that separates URL and filename. It seems to be a limit in PowerShell Invoke-WebRequest that limits this downloads to some like 128MB
|
||||
- EXIT: Terminates a cook in this instruction. If a param is specified, exit will be with error code and the param as text of error. (Ej: EXIT|Error at seeking for file)
|
||||
|
||||
## If types
|
||||
Inside a cook, you can use IF/ELSE/ENDIF scheme.
|
||||
- IFSOFTWAREINST: Runs the if, if a program is installed.
|
||||
- IFSOFTWAREVER: Runs the if, if a program is installed and has X version. (Run with two param: "Name;Version")
|
||||
- IFPATHEXISTS: Runs if file exists
|
||||
- IFPWCMD: If powershell command returns $true (Executed succesfully), if is run
|
||||
- ELSE: Else..
|
||||
- ENDIF
|
||||
|
||||
3
doc/naming_limits.md
Normal file
3
doc/naming_limits.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Cooks have to be only alfanumeric caracters and "-","_" and must end with .yaml
|
||||
|
||||
Groups have to be alfanumeric and "-","_"
|
||||
3
loadserver.bat
Normal file
3
loadserver.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
REM Starting Server. Will only work if python and dependencies are installed and in PATH
|
||||
cd /D "%~dp0"
|
||||
waitress-serve --port=3333 api:api
|
||||
3
loadserver.sh
Normal file
3
loadserver.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$(realpath "$0")")";
|
||||
waitress-serve --port=3333 api:api
|
||||
45
sql.py
Normal file
45
sql.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import sqlite3
|
||||
import sysopt #File of options
|
||||
from shutil import copyfile
|
||||
from os import path
|
||||
from datetime import datetime
|
||||
|
||||
if not path.isfile('BD/database.db'):
|
||||
copyfile('BD/emptydatabase.db','BD/database.db')
|
||||
|
||||
def logit(text):
|
||||
text = str(text)
|
||||
now = datetime.now()
|
||||
print ("Log: " + text)
|
||||
with open('api.log', 'a') as file:
|
||||
file.write("Log ("+now.strftime("%x %X") + "): ")
|
||||
file.write(text)
|
||||
file.write('\n')
|
||||
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
|
||||
|
||||
def select(query):
|
||||
conn = sqlite3.connect('BD/database.db')
|
||||
conn.row_factory = dict_factory
|
||||
if sysopt.debugsql==True:
|
||||
logit("SQL: "+query)
|
||||
cur = conn.execute(query)
|
||||
return cur.fetchall()
|
||||
|
||||
def insert(query):
|
||||
conn = sqlite3.connect('BD/database.db')
|
||||
if sysopt.debugsql==True:
|
||||
logit(query)
|
||||
try:
|
||||
c = conn.cursor()
|
||||
c.execute("SQL: "+query)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return {'RESULT': 'OK'}
|
||||
except:
|
||||
return {'RESULT': 'SQLite3 Error'}
|
||||
Reference in New Issue
Block a user