mirror of
https://gitlab.com/JKANetwork/powerfulcomputermanager.git
synced 2026-02-22 13:03:43 +01:00
Changes to doc and api/app for be able to record more things
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,11 +3,10 @@
|
||||
*.log
|
||||
*.out
|
||||
client/configpcm.ini
|
||||
client/client.sh
|
||||
BD/database*
|
||||
reports/
|
||||
__pycache__/
|
||||
**/__pycache__/
|
||||
.vscode/
|
||||
cooks/*.yaml
|
||||
control/
|
||||
_site
|
||||
Binary file not shown.
@@ -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
|
||||
- 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)
|
||||
|
||||
- Support Linux clients
|
||||
|
||||
# Requirements
|
||||
|
||||
|
||||
25
api.py
25
api.py
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
BUILD = 21
|
||||
BUILD = 24
|
||||
API_VER = 1
|
||||
##It can be run directly with "waitress-serve --port=3333 api:api"
|
||||
import falcon
|
||||
@@ -10,7 +10,7 @@ import sql # SQL work file
|
||||
import json,yaml
|
||||
from datetime import datetime
|
||||
|
||||
import sysopt #File of options
|
||||
sqlAddComputers = sql.retOption('AddComputers')
|
||||
|
||||
def logit(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
|
||||
response.media = {'TEXT': 'Error, computer and UUID doesn\'t match in database', 'RESULT': 'ERROR','EXITCODE':'2'}
|
||||
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+"')")
|
||||
response.media = {'RESULT': '1'}
|
||||
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+"'")
|
||||
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):
|
||||
def on_get(self, request, response):
|
||||
logit(request)
|
||||
ComputerID, UUID, Password= None, None,None
|
||||
ComputerID, UUID = None, None
|
||||
for key, value in request.params.items():
|
||||
if key == "ComputerName":
|
||||
try:
|
||||
@@ -587,10 +593,6 @@ class updComputer(object):
|
||||
ComputerID = value
|
||||
if key == "UUID":
|
||||
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:
|
||||
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:
|
||||
@@ -613,6 +615,10 @@ class updComputer(object):
|
||||
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+"'")
|
||||
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
|
||||
@@ -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/statuscook', getStatusCook()) # See status of a cook
|
||||
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/computer', updComputer()) #Update data of computer
|
||||
api.add_route('/upd/cookname', updCookName()) #Update file name of cook and SQL references to it.
|
||||
|
||||
@@ -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)
|
||||
@@ -1,13 +1,13 @@
|
||||
# Build 9
|
||||
# Build 11
|
||||
param([Int32]$startup=0)
|
||||
Write-Host $startup
|
||||
$root = $PSCommandPath | Split-Path -Parent
|
||||
$server = (Get-Content "$root\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).server
|
||||
$resources = (Get-Content "$root\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).resources
|
||||
#Write-Host $startup
|
||||
$srcdir = $PSCommandPath | Split-Path -Parent
|
||||
$server = (Get-Content "$srcdir\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).server
|
||||
$resources = (Get-Content "$srcdir\configpcm.ini" | select -Skip 1 | ConvertFrom-StringData).resources
|
||||
$64bit = [Environment]::Is64BitOperatingSystem
|
||||
|
||||
$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"
|
||||
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
|
||||
$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
|
||||
$CPUInfo = (Get-CimInstance Win32_Processor) | Select Name,MaxClockSpeed,ThreadCount
|
||||
$CPUName = -join($CPUInfo.ThreadCount, " x ",$CPUInfo.Name.Trim()," (",$CPUInfo.MaxClockSpeed," MHz)")
|
||||
$RAMInstalled = Get-CimInstance CIM_PhysicalMemory | Measure-Object -Property capacity -Sum | ForEach-Object {[math]::round(($_.sum / 1MB),2)}
|
||||
$RAMFree = [Math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory/1024,0)
|
||||
$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
|
||||
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"
|
||||
|
||||
foreach ($CookName in $cooks){
|
||||
|
||||
@@ -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"
|
||||
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.
|
||||
|
||||
# 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)
|
||||
# Commands avaiable (LINUX IS NOT SUPPORTED YET)
|
||||
|
||||
| OS | COMMAND | Description |
|
||||
|----- |------------- |--------------------------------------------------------------------------------------------------------- |
|
||||
| W | CMD | Cmd command. Beware of quotes, because internally is run as cmd /c "" |
|
||||
| W/L | PWCMD | Powershell command, runs using Invoke-Command |
|
||||
| W/L | REPOTOLOCAL | Copy a file from REPO folder configured to local in temp folder. You can copy a file or a folder |
|
||||
| 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) |
|
||||
| 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 |
|
||||
| W/L | ENDNOERROR | Finishes NOERROR Block |
|
||||
| W/L | SERV_ENABLE | Enables a service |
|
||||
| W/L | SERV_DISABLE | Disables a service |
|
||||
| W/L | MSG | Shows a message to user |
|
||||
| W/L | REM / COMMENT | Annotation for developers in cooks |
|
||||
| W/L | KILL_PROCESS | Kills a process |
|
||||
| W/L | UNINSTALL | Uninstalls a software by name. (It finishes using * at Windows 'Get-Package -Name "Program*"', be care) |
|
||||
| W/L | REMOVE | Removes a file or folder path from local compuer. It's recursive |
|
||||
| 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
19
sql.py
@@ -1,6 +1,5 @@
|
||||
# Build 2
|
||||
# Build 3
|
||||
import sqlite3
|
||||
import sysopt #File of options
|
||||
from shutil import copyfile
|
||||
from os import path
|
||||
from datetime import datetime
|
||||
@@ -27,24 +26,32 @@ def dict_factory(cursor, row):
|
||||
def select(query):
|
||||
conn = sqlite3.connect('BD/database.db')
|
||||
conn.row_factory = dict_factory
|
||||
if sysopt.debugsql==True:
|
||||
if 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:
|
||||
if debugsql==True:
|
||||
logit("SQL: "+query)
|
||||
try:
|
||||
c = conn.cursor()
|
||||
c.execute(query)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
if sysopt.debugsql==True:
|
||||
if debugsql==True:
|
||||
logit("SQL Ok")
|
||||
return {'RESULT': 'OK'}
|
||||
except:
|
||||
if sysopt.debugsql==True:
|
||||
if debugsql==True:
|
||||
logit("SQL 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')
|
||||
Reference in New Issue
Block a user