Changes to doc and api/app for be able to record more things

This commit is contained in:
2019-11-19 09:01:26 +01:00
parent 9de38014be
commit cbe562da96
9 changed files with 105 additions and 140 deletions

3
.gitignore vendored
View File

@@ -3,11 +3,10 @@
*.log *.log
*.out *.out
client/configpcm.ini client/configpcm.ini
client/client.sh
BD/database* BD/database*
reports/
__pycache__/ __pycache__/
**/__pycache__/ **/__pycache__/
.vscode/ .vscode/
cooks/*.yaml cooks/*.yaml
control/ control/
_site

Binary file not shown.

View File

@@ -17,7 +17,7 @@ It's not error proof, then, I don't have any responsability if something crashes
- Somewhat more security in API 1 - Somewhat more security in API 1
- Stabilize all - Stabilize all
- I created a simple GUI in EasyGUI to be easy used, but if I have time, maybe will do a webUI more dynamic and visually better (Without needing to install php/apache/nginx, using python) - I created a simple GUI in EasyGUI to be easy used, but if I have time, maybe will do a webUI more dynamic and visually better (Without needing to install php/apache/nginx, using python)
- Support Linux clients
# Requirements # Requirements

25
api.py
View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!/usr/bin/python3
BUILD = 21 BUILD = 24
API_VER = 1 API_VER = 1
##It can be run directly with "waitress-serve --port=3333 api:api" ##It can be run directly with "waitress-serve --port=3333 api:api"
import falcon import falcon
@@ -10,7 +10,7 @@ import sql # SQL work file
import json,yaml import json,yaml
from datetime import datetime from datetime import datetime
import sysopt #File of options sqlAddComputers = sql.retOption('AddComputers')
def logit(text): def logit(text):
text = str(text) text = str(text)
@@ -60,7 +60,7 @@ class getComputerExists(object):
elif sql.select("SELECT COUNT(*) 'RESULT' FROM COMPUTERS WHERE Name='"+ComputerName+"'")[0]['RESULT'] != 0: #Not UUID match, but computer exists elif sql.select("SELECT COUNT(*) 'RESULT' FROM COMPUTERS WHERE Name='"+ComputerName+"'")[0]['RESULT'] != 0: #Not UUID match, but computer exists
response.media = {'TEXT': 'Error, computer and UUID doesn\'t match in database', 'RESULT': 'ERROR','EXITCODE':'2'} response.media = {'TEXT': 'Error, computer and UUID doesn\'t match in database', 'RESULT': 'ERROR','EXITCODE':'2'}
return return
if sysopt.addComputers == True: #Computer doesn't exist, but you have enabled add all computers if sqlAddComputers == True: #Computer doesn't exist, but you have enabled add all computers
sql.insert("INSERT INTO COMPUTERS (`Name`,`UUID`) VALUES('"+ComputerName+"','"+UUID+"')") sql.insert("INSERT INTO COMPUTERS (`Name`,`UUID`) VALUES('"+ComputerName+"','"+UUID+"')")
response.media = {'RESULT': '1'} response.media = {'RESULT': '1'}
else: #Computer doesn't exist and you don't want to be added else: #Computer doesn't exist and you don't want to be added
@@ -571,11 +571,17 @@ class delComputer(object): #Delete computer
resp = sql.insert("DELETE FROM COMPUTERS WHERE ID_C='"+ComputerID+"'") resp = sql.insert("DELETE FROM COMPUTERS WHERE ID_C='"+ComputerID+"'")
logit(resp) logit(resp)
##
# updComputer: Upd computer data
# /upd/computer?
# @param ComputerID -> Computer ID
# @param UUID -> UUID of computer
# No need password, validate from ComputerID+UUID for updates..
##
class updComputer(object): class updComputer(object):
def on_get(self, request, response): def on_get(self, request, response):
logit(request) logit(request)
ComputerID, UUID, Password= None, None,None ComputerID, UUID = None, None
for key, value in request.params.items(): for key, value in request.params.items():
if key == "ComputerName": if key == "ComputerName":
try: try:
@@ -587,10 +593,6 @@ class updComputer(object):
ComputerID = value ComputerID = value
if key == "UUID": if key == "UUID":
UUID = value UUID = value
if key == "Password" and value == retPassword():
Password=value
if Password is None:
response.media = {'TEXT': 'Invalid password','RESULT':'ERROR'}
if ComputerID is None and response.media is None: if ComputerID is None and response.media is None:
response.media = {'TEXT': 'Error, you need a ComputerName/ComputerID to update data','RESULT':'ERROR'} response.media = {'TEXT': 'Error, you need a ComputerName/ComputerID to update data','RESULT':'ERROR'}
elif response.media is None and ComputerID is not None and UUID is not None: elif response.media is None and ComputerID is not None and UUID is not None:
@@ -613,6 +615,10 @@ class updComputer(object):
response.media = sql.insert("UPDATE COMPUTERS SET RAM='"+value+"' WHERE ID_C='"+ComputerID+"'") response.media = sql.insert("UPDATE COMPUTERS SET RAM='"+value+"' WHERE ID_C='"+ComputerID+"'")
if key == "CPUName": if key == "CPUName":
response.media = sql.insert("UPDATE COMPUTERS SET CPUName='"+value+"' WHERE ID_C='"+ComputerID+"'") response.media = sql.insert("UPDATE COMPUTERS SET CPUName='"+value+"' WHERE ID_C='"+ComputerID+"'")
if key == "RAMFree":
response.media = sql.insert("UPDATE COMPUTERS SET RAMFree='"+str(value)+"' WHERE ID_C='"+ComputerID+"'")
if key == "HDD":
response.media = sql.insert("UPDATE COMPUTERS SET HDD='"+str(value)+"' WHERE ID_C='"+ComputerID+"'")
## ##
# updCookName: Rename cook name # updCookName: Rename cook name
@@ -809,7 +815,6 @@ api.add_route('/get/grpcook', getGrpCook()) # See groups of a determinated cook
api.add_route('/get/lastrevisioncook', getLastRevisionCook()) # Returns number of last revision of a cook api.add_route('/get/lastrevisioncook', getLastRevisionCook()) # Returns number of last revision of a cook
api.add_route('/get/statuscook', getStatusCook()) # See status of a cook api.add_route('/get/statuscook', getStatusCook()) # See status of a cook
api.add_route('/load/cook', loadCook()) # Load a cook (Transfer in json way) 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 (OLD)
api.add_route('/upd/cookstatus', setCookStatus()) # Update status of a cook in a computer api.add_route('/upd/cookstatus', setCookStatus()) # Update status of a cook in a computer
api.add_route('/upd/computer', updComputer()) #Update data of computer 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('/upd/cookname', updCookName()) #Update file name of cook and SQL references to it.

View File

@@ -1,76 +0,0 @@
$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)

View File

@@ -1,13 +1,13 @@
# Build 9 # Build 11
param([Int32]$startup=0) param([Int32]$startup=0)
Write-Host $startup #Write-Host $startup
$root = $PSCommandPath | Split-Path -Parent $srcdir = $PSCommandPath | Split-Path -Parent
$server = (Get-Content "$root\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).server $server = (Get-Content "$srcdir\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).server
$resources = (Get-Content "$root\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).resources $resources = (Get-Content "$srcdir\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).resources
$64bit = [Environment]::Is64BitOperatingSystem $64bit = [Environment]::Is64BitOperatingSystem
$computerName = [System.Net.Dns]::GetHostName() $computerName = [System.Net.Dns]::GetHostName()
$UUID=(get-wmiobject Win32_ComputerSystemProduct).UUID $UUID=(Get-CimInstance Win32_ComputerSystemProduct).UUID
$exists = Invoke-RestMethod -Method Get -Uri "$server/get/computerexists?ComputerName=$computerName&UUID=$UUID" $exists = Invoke-RestMethod -Method Get -Uri "$server/get/computerexists?ComputerName=$computerName&UUID=$UUID"
if ($exists.Result -eq "ERROR"){ if ($exists.Result -eq "ERROR"){
@@ -29,15 +29,35 @@ if ($SOVersion -match "^10.0."){ #If its Windows 10, add revision number for kno
} }
# Update Computer Data # Update Computer Data
$CPUInfo = Get-WmiObject Win32_Processor $CPUInfo = (Get-CimInstance Win32_Processor) | Select Name,MaxClockSpeed,ThreadCount
$RAMInstalled = Get-WmiObject CIM_PhysicalMemory | Measure-Object -Property capacity -Sum | ForEach-Object {[math]::round(($_.sum / 1MB),2)} $CPUName = -join($CPUInfo.ThreadCount, " x ",$CPUInfo.Name.Trim()," (",$CPUInfo.MaxClockSpeed," MHz)")
$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) $RAMInstalled = Get-CimInstance CIM_PhysicalMemory | Measure-Object -Property capacity -Sum | ForEach-Object {[math]::round(($_.sum / 1MB),2)}
Invoke-RestMethod -Method Get -Uri $paramInvoke | out-null $RAMFree = [Math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory/1024,0)
# More info $RAMUsed = $RamInstalled-$RAMFree
# Disks
$objDisks = Get-CimInstance -Class win32_LogicalDisk -Filter "DriveType = '3'"
$diskResults = @()
ForEach( $disk in $objDisks )
{
$ThisVolume = "" | select Volume,Capacity,FreeSpace
$ThisVolume.Volume = $disk.DeviceID
$ThisVolume.Capacity = $([Math]::Round($disk.Size / 1GB,2))
$ThisVolume.FreeSpace = $([Math]::Round($disk.FreeSpace / 1GB,2))
$DiskResults += $ThisVolume
}
$DisksData = $DiskResults |ConvertTo-Json
$DisksData = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($DisksData)) #I can't enter to database all without encode
$lastUser = (Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName -ComputerName .).UserName $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 # Send it
$paramInvoke = -join("$server/upd/computer?ComputerName=$computerName&UUID=",$UUID,"&SOVersion=",$SOVersion,"&SOCaption=",$SOData.Caption,"&SOBit=",$SOData.OsArchitecture.Substring(0,2),"&LastConnection=",$Timestamp,"&RAM=",$RAMInstalled,"&RAMFree=",$RAMFree,"&CPUName=",$CPUName,"&LastUser=",$lastUser,"&HDD=",$DisksData)
Invoke-RestMethod -Method Get -Uri $paramInvoke | out-null
# More info (Only if has to be)
# $paramInvoke = -join("$server/upd/computerhis?ComputerName=$computerName&UUID=",$UUID,"&RAMFree=",$RAMFree,"&RAMUsed=",$RAMUsed,"&Timestamp=",$Timestamp,"&DisksUse=",$disksUse)
# Invoke-RestMethod -Method Get -Uri $paramInvoke | out-null
# Load Cooks of computer
$cooks = Invoke-RestMethod -Method Get -Uri "$server/get/cookpend?ComputerName=$computerName&UUID=$UUID" $cooks = Invoke-RestMethod -Method Get -Uri "$server/get/cookpend?ComputerName=$computerName&UUID=$UUID"
foreach ($CookName in $cooks){ foreach ($CookName in $cooks){

View File

@@ -21,37 +21,50 @@ And then, steps. First a "steps:" line, and then line by line the steps of the c
Steps are ever put like "Type of step" | "Command" 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" 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. Cook finishes executing if they had and error (Except inside a NOERROR block), or if finishes right.
You have examples in the example_cooks folder
Note: Cooks start in directory $env:temp (%TEMP%) from SYSTEM user. Note: Cooks start in directory $env:temp (%TEMP%) from SYSTEM user.
# Type of commands # Commands avaiable (LINUX IS NOT SUPPORTED YET)
- 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. | OS | COMMAND | Description |
- 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 | W | CMD | Cmd command. Beware of quotes, because internally is run as cmd /c "" |
Example: | W/L | PWCMD | Powershell command, runs using Invoke-Command |
NOERROR|For deleting a file that maybe can not exist | W/L | REPOTOLOCAL | Copy a file from REPO folder configured to local in temp folder. You can copy a file or a folder |
PWCMD|Remove-Item C:\Windows\loginstall.txt | W | 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) |
ENDNOERROR|Finish | W/L | NOERROR | Creates a block of instructions that not captures errors and continues event if fails<br>Example:<br>NOERROR|Try to delete a file that maybe can not exist<br>PWCMD|Remove-Item C:\Windows\loginstall.txt<br>ENDNOERROR|Finish |
- SERV_DISABLE and SERV_ENABLE: Enables or disables a Windows Service | W/L | ENDNOERROR | Finishes NOERROR Block |
- MSG|Display a message to user | W/L | SERV_ENABLE | Enables a service |
- COMMENT or REM: Makes cook comments (COMMENT|This is a comment) | W/L | SERV_DISABLE | Disables a service |
- KILL_PROCESS: Kill a process name if exists | W/L | MSG | Shows a message to user |
- 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 | W/L | REM / COMMENT | Annotation for developers in cooks |
- REMOVE: Removes a file or folder path from local computer. It's recursive | W/L | KILL_PROCESS | Kills a process |
- SLEEP and PAUSE: Pauses execution seconds specified in param | W/L | UNINSTALL | Uninstalls a software by name. (It finishes using * at Windows 'Get-Package -Name "Program*"', be care) |
- 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 | W/L | REMOVE | Removes a file or folder path from local compuer. It's recursive |
- 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) | W/L | SLEEP / PAUSE | Pauses execution seconds specified in param (SLEEP|3) |
| W/L | DOWNLOAD * | Downloads a file from network to tempFolder/filename. It's required to put a filename like: DOWNLOAD|http://example.org/file.zip;filename.zip. ";" separates URL and filename |
| W/L | EXIT | Terminates cook execution. It can take a param as error text (EXIT|Error at removing file) |
| L | BASH | Bash command |
- *DOWNLOAD: It seems to be a limit in PowerShell Invoke-WebRequest that limits this downloads to some like 128MB
Inside of a Cook, you can use a simple IF query:
| OS | COMMAND | Runs if when: |
|----- |----------------- |--------------------------------------------------------------------------------- |
| W/L | IFSOFTWAREINST | When program is installed. |
| W/L | IFSOFTWAREVER | When program is installed and has X version (Name;Version) |
| W/L | IFPATHEXISTS | When if file exists |
| W/L | IFPWCMD | When powershell command returns True (Beware of command executed if using Linux) |
| W/L | IF64BIT | When computer is running a 64 Bit operating system |
| W/L | IF32BIT | When computer is running a 32 Bit operating system |
| W/L | IFWINDOWS | When computer is running Windows |
| W/L | IFLINUX | When computer is running Linux |
| L | IFBASH | When bash command returns True |
| W/L | ELSE | Else of IF... |
| W/L | ENDIF | Finishes IF block |
## 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
- IF64BIT: If you are in a 64 Bit operating system
- IF32BIT: If you are in a 32 Bit operating system
- ELSE: Else..
- ENDIF

19
sql.py
View File

@@ -1,6 +1,5 @@
# Build 2 # Build 3
import sqlite3 import sqlite3
import sysopt #File of options
from shutil import copyfile from shutil import copyfile
from os import path from os import path
from datetime import datetime from datetime import datetime
@@ -27,24 +26,32 @@ def dict_factory(cursor, row):
def select(query): def select(query):
conn = sqlite3.connect('BD/database.db') conn = sqlite3.connect('BD/database.db')
conn.row_factory = dict_factory conn.row_factory = dict_factory
if sysopt.debugsql==True: if debugsql==True:
logit("SQL: "+query) logit("SQL: "+query)
cur = conn.execute(query) cur = conn.execute(query)
return cur.fetchall() return cur.fetchall()
def insert(query): def insert(query):
conn = sqlite3.connect('BD/database.db') conn = sqlite3.connect('BD/database.db')
if sysopt.debugsql==True: if debugsql==True:
logit("SQL: "+query) logit("SQL: "+query)
try: try:
c = conn.cursor() c = conn.cursor()
c.execute(query) c.execute(query)
conn.commit() conn.commit()
conn.close() conn.close()
if sysopt.debugsql==True: if debugsql==True:
logit("SQL Ok") logit("SQL Ok")
return {'RESULT': 'OK'} return {'RESULT': 'OK'}
except: except:
if sysopt.debugsql==True: if debugsql==True:
logit("SQL Error") logit("SQL Error")
return {'RESULT': 'SQLite3 Error'} return {'RESULT': 'SQLite3 Error'}
def retOption(option):
try:
return select("SELECT Value FROM OPTIONS WHERE Option='"+option+"'")[0]['Value']
except:
return None
debugsql = retOption('DebugSQL')

View File

@@ -1,3 +0,0 @@
addComputers = False # False/True accept auto add computers that start client program and connect to server
debugsql = False # True is show in log all SQL queries