# Build 21. Using API 2 param([Int32]$startup=0) $host.UI.RawUI.WindowTitle = "Powerful Computer Manager - Do Not Close" Write-Host "Starting Powerful Computer Manager..." $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-CimInstance Win32_ComputerSystemProduct).UUID # Powershell of Windows / Powershell Core if ((Get-Host | Select-Object Version).Version.Major -lt 6){#Powershell Windows (Not Core) Powershell < 6 add-type -TypeDefinition @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy }else{ # Powershell Core $PSDefaultParameterValues += @{'Invoke-RestMethod:SkipCertificateCheck' = $true} } # Force install nuget if not installed (If not installed, it breaks uninstalls silently) If(-not(Get-PackageProvider NuGet -ErrorAction silentlycontinue)){ Install-PackageProvider -Name NuGet -Confirm:$False -Force } $exists = Invoke-RestMethod -Method Post -Uri "$server/get/computerexists?ComputerName=$computerName&UUID=$UUID" if ($exists.Result -eq "ERROR"){ if ($exists.EXITCODE -eq '3'){ Write-Host "Computer outside database:" $computerName }else{ Write-Host "Computer and UUID of $computerName doesn't match" } 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-CimInstance Win32_Processor) | Select-Object 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-Object Volume,Capacity,UsedSpace,FreeSpace $ThisVolume.Volume = $disk.DeviceID $ThisVolume.Capacity = $([Math]::Round($disk.Size / 1GB,2)) $ThisVolume.FreeSpace = $([Math]::Round($disk.FreeSpace / 1GB,2)) $ThisVolume.UsedSpace = $([Math]::Round(($disk.Size - $disk.FreeSpace) / 1GB,2)) $DiskResults += $ThisVolume } $DisksData = ConvertTo-Json -Depth 4 $DiskResults $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 # 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 Post -Uri $paramInvoke | out-null # Load Cooks of computer $cooks = Invoke-RestMethod -Method Post -Uri "$server/get/cookpend?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 Post -Uri "$server/load/cook?CookName=$CookName&ComputerName=$computerName&UUID=$UUID" Write-Host "Receta:" $cook.name $CookRevision = $cook.revision $atstartup = $cook.atstartup if ($atstartup -eq 1 -and $startup -ne 1){ # If script has to tun at startup of computer, and there is not this moment.. Write-Host "Se salta ya que no esta arrancando/apagandose el equipo..." continue # Go for next } if ($cook.only64bit -eq 1 -and $64bit -eq $False) { # If script is only for 64 bit and system is 32 bit.. Write-Host "Se salta ya que es esta receta es solo para 64 bits..." continue # Go for next } if ($cook.only32bit -eq 1 -and $64bit -eq $True) { # If script is only for 32 bit and system is 64 bit.. Write-Host "Se salta ya que es esta receta es solo para 32 bits..." continue # Go for next } $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] $param2 = $step[2] 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 # YOU HAVE TO CHECK IF NUGET IS INSTALLED, IF NOT, EXIT AS Error (If not doing this, program will stuck) If(-not(Get-PackageProvider NuGet -ErrorAction silentlycontinue)){ Write-Host "You don't have NuGet installed! Aborting..." $err = 1 }else{ # Uninstall package 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 } } {$_ -in "KILL_PROCESS","KILLPROCESS"} { $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 #} } } "CD" { #CHANGE DIR, ITS DANGEROUS. IF PARAM IS EMPTY, GO TO $env:temp if ($param -eq ""){ Set-Location "$env:temp" }else{ Set-Location "$param" } if ($? -eq $false){ # Location change error $err = 1 } } "CMD" { # Run a cmd command. Note: Runs at high priv. cmd.exe /c "$param" if ($LASTEXITCODE -ne 0){ # 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 } } "PWSCRIPT" { # Run a powershell script. Note: Runs as high priv. Invoke-Expression -Command $param if ($? -eq $false){ # Error in Script $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 } "COPY" { # Copy file from repo location to some folder $parts = $param.Split(";") if ($parts[1] -ne ""){ #Exists orig and dest $orig=$parts[0] $dest=$parts[1] Copy-Item "$orig" "$dest" -ErrorVariable errvar -Recurse -Force if ($? -eq $False){ # Error in Copy $err = 1 } }else{ #Doesn't sent right $err = 1 $errvar = "Param not set right. Exiting..." } } "REMOVE" { # Remove files / folders Remove-Item "$param" -Recurse -Force -ErrorAction Continue # They not see errors (Because error will be file not found) } {$_ -in "INSTALLMSI","MSIINSTALL"} { # 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 } "IFCOMPUTERNAME" { # If Computer Name is something $inif = $true #This controls IF start/stop $cname = (Get-ComputerName).CSName if ($cname -eq "$param"){ $if = $True }else{ $if = $False } # True -> Exists ; False -> Not exists } "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 } "IF64BIT" { # If 64 bit computer $inif = $True $if = $64bit # Its true if 64 bit computer } "IF32BIT" { # If 32 bit computer $inif = $True $if = !$64bit # Its true if 32 bit computer, flipped boolean } "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 { ##DEFAULT, SAY COMMAND NOT VALID Write-Host "Command not valid." } } } # 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 Post -Uri "$server/set/cookstatus?ComputerName=$computerName&UUID=$UUID&CookName=$CookName&Revision=$CookRevision&Error=$err&ErrorDesc=$errvar" | out-null #Return to $env:temp Set-Location "$env:temp" #Delete files copied to temp for saving space foreach ($element in $filesCopied) { Remove-Item "$env:temp\$element" -ErrorAction SilentlyContinue -Recurse -Force } }