ViewPower nu putea dialoga cu acest UPS: 5777 de "QPI return(NAK" si zero citiri reusite in fereastra 6-10 august, pentru ca UPS-ul vorbeste HID Power Device standard, nu dialectul text Voltronic. Serviciile au fost dezactivate pe 10.08.2026 la 22:34, lasand serverul fara nicio alertare 17 zile. Nici inainte nu exista: emailReceivers = 0, iar excuteProgram era gol, deci Oracle nu era oprit curat oricum. UPS-ul comunica insa perfect cu Windows pe canalul HID - dovedit de perechile de evenimente Kernel-Power 105 la panele reale din 2026. Monitorul nou citeste GetSystemPowerStatus, acelasi semnal pe care il foloseste Windows pentru propria actiune la baterie critica. Alerteaza pe email la trecerea pe baterie, la revenirea curentului si cand UPS-ul nu mai comunica - cazul care a trecut neobservat. Opreste curat listenerul, apoi instanta cu shutdown immediate, apoi Windows-ul, inaintea pragului brutal de 20% al Windows-ului. Ruleaza ca task programat sub SYSTEM, cu AllowStartIfOnBatteries si DontStopIfGoingOnBatteries - fara ele Windows ar fi oprit taskul exact cand serverul trece pe baterie. Validat pe 27.08.2026: citire, email, secventa de oprire in dry-run si pierderea comunicatiei (alerta la exact 8 cicluri, apoi revenire). Pragurile de 10 min / 35% sunt conservatoare, nu masurate - testul de autonomie reala ramane de facut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRyaDj39hPQ89SZS6URRpS
198 lines
8.0 KiB
PowerShell
198 lines
8.0 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Instaleaza monitorizarea UPS pe serverul Oracle de productie: copiaza scriptul,
|
|
scrie config.json, restrictioneaza drepturile si inregistreaza taskul programat.
|
|
|
|
.DESCRIPTION
|
|
Se ruleaza PE SERVER, dintr-un PowerShell ridicat (Administrator).
|
|
|
|
Taskul ruleaza ca NT AUTHORITY\SYSTEM - cont care e deja membru ORA_DBA pe acest
|
|
server, deci "sqlplus / as sysdba" merge fara parola.
|
|
|
|
Doua detalii care fac diferenta si sunt usor de ratat:
|
|
- AllowStartIfOnBatteries + DontStopIfGoingOnBatteries: fara ele, Windows
|
|
opreste taskul exact cand serverul trece pe baterie, adica exact cand ai
|
|
nevoie de el;
|
|
- al doilea declansator, care repeta la 10 minute cu MultipleInstances=IgnoreNew:
|
|
daca procesul moare, revine singur; daca traieste, pornirea e ignorata.
|
|
|
|
.PARAMETER SmtpPassword
|
|
Parola contului SMTP. Ajunge in config.json, care primeste ACL doar pentru
|
|
SYSTEM si Administratori. NU se comiteaza in git.
|
|
|
|
.PARAMETER Uninstall
|
|
Sterge taskul programat. Nu sterge directorul, logurile sau configuratia.
|
|
|
|
.EXAMPLE
|
|
powershell -ExecutionPolicy Bypass -File .\install-ups-monitor.ps1 -SmtpPassword '...'
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$InstallDir = 'C:\ROMFAST\ups-monitor',
|
|
|
|
[string]$SmtpServer = 'mail.romfast.ro',
|
|
[int]$SmtpPort = 587,
|
|
[string]$SmtpUser = 'ups@romfast.ro',
|
|
[string]$SmtpFrom = 'ups@romfast.ro',
|
|
[string]$SmtpPassword,
|
|
|
|
[string[]]$MailTo = @('marius.mutu@romfast.ro'),
|
|
|
|
[int]$PollSeconds = 15,
|
|
[int]$ShutdownAfterMinutesOnBattery = 10,
|
|
[int]$ShutdownAtBatteryPercent = 35,
|
|
|
|
[string]$OracleHome = 'C:\Users\Administrator\Downloads\WINDOWS.X64_193000_db_home',
|
|
[string]$OracleSid = 'ROA',
|
|
[string]$OracleService = 'OracleServiceROA',
|
|
[string]$OracleListenerService = 'OracleOraDB19Home1TNSListener',
|
|
[int]$OracleShutdownTimeoutSeconds = 180,
|
|
|
|
[switch]$Uninstall
|
|
)
|
|
|
|
Set-StrictMode -Version 2.0
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$TaskName = 'ROMFAST UPS Monitor'
|
|
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
|
|
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
throw 'Scriptul trebuie rulat dintr-un PowerShell ridicat (Administrator).'
|
|
}
|
|
|
|
if ($Uninstall) {
|
|
if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
|
|
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
|
|
Write-Host "Task '$TaskName' sters. Directorul $InstallDir a ramas pe loc."
|
|
} else {
|
|
Write-Host "Taskul '$TaskName' nu era inregistrat."
|
|
}
|
|
return
|
|
}
|
|
|
|
if (-not $SmtpPassword) {
|
|
throw 'Lipseste -SmtpPassword. Fara el nu pleaca nicio alerta.'
|
|
}
|
|
|
|
# --- fisiere ---------------------------------------------------------------
|
|
|
|
$logDir = Join-Path $InstallDir 'log'
|
|
foreach ($d in @($InstallDir, $logDir)) {
|
|
if (-not (Test-Path -LiteralPath $d)) {
|
|
New-Item -ItemType Directory -Path $d -Force | Out-Null
|
|
}
|
|
}
|
|
|
|
$sourceScript = Join-Path $PSScriptRoot 'ups-monitor.ps1'
|
|
if (-not (Test-Path -LiteralPath $sourceScript)) {
|
|
throw "Nu gasesc ups-monitor.ps1 langa install-ups-monitor.ps1 ($sourceScript)"
|
|
}
|
|
Copy-Item -LiteralPath $sourceScript -Destination $InstallDir -Force
|
|
Write-Host "Copiat ups-monitor.ps1 in $InstallDir"
|
|
|
|
$config = [ordered]@{
|
|
enabled = $true
|
|
pollSeconds = $PollSeconds
|
|
shutdownAfterMinutesOnBattery = $ShutdownAfterMinutesOnBattery
|
|
shutdownAtBatteryPercent = $ShutdownAtBatteryPercent
|
|
shutdownAtRuntimeSeconds = 0
|
|
confirmPolls = 3
|
|
commsLostPolls = 8
|
|
commsAlertRepeatHours = 24
|
|
logPath = $logDir
|
|
stateFile = (Join-Path $InstallDir 'state.json')
|
|
mailTo = $MailTo
|
|
smtp = [ordered]@{
|
|
server = $SmtpServer
|
|
port = $SmtpPort
|
|
user = $SmtpUser
|
|
password = $SmtpPassword
|
|
from = $SmtpFrom
|
|
}
|
|
oracle = [ordered]@{
|
|
home = $OracleHome
|
|
sid = $OracleSid
|
|
service = $OracleService
|
|
listenerService = $OracleListenerService
|
|
shutdownTimeoutSeconds = $OracleShutdownTimeoutSeconds
|
|
}
|
|
}
|
|
|
|
$configPath = Join-Path $InstallDir 'config.json'
|
|
$config | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $configPath -Encoding UTF8
|
|
Write-Host "Scris $configPath"
|
|
|
|
# --- drepturi: config.json contine parola SMTP ------------------------------
|
|
|
|
$acl = Get-Acl -LiteralPath $InstallDir
|
|
$acl.SetAccessRuleProtection($true, $false) # taie mostenirea, fara sa copieze regulile
|
|
foreach ($r in @($acl.Access)) { $acl.RemoveAccessRule($r) | Out-Null }
|
|
foreach ($who in @('NT AUTHORITY\SYSTEM', 'BUILTIN\Administrators')) {
|
|
$acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule(
|
|
$who, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow')))
|
|
}
|
|
Set-Acl -LiteralPath $InstallDir -AclObject $acl
|
|
Write-Host "Drepturi restranse pe $InstallDir : doar SYSTEM si Administratori"
|
|
|
|
# --- verificari inainte de inregistrare -------------------------------------
|
|
|
|
foreach ($svc in @($OracleService, $OracleListenerService)) {
|
|
if (-not (Get-Service -Name $svc -ErrorAction SilentlyContinue)) {
|
|
Write-Warning "Serviciul '$svc' nu exista pe acest server - verifica parametrii Oracle."
|
|
}
|
|
}
|
|
if (-not (Test-Path -LiteralPath (Join-Path $OracleHome 'bin\sqlplus.exe'))) {
|
|
Write-Warning "sqlplus.exe nu e la $OracleHome\bin - oprirea va cadea pe Stop-Service."
|
|
}
|
|
|
|
# --- taskul programat -------------------------------------------------------
|
|
|
|
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument (
|
|
'-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "{0}\ups-monitor.ps1" -Mode Run' -f $InstallDir)
|
|
|
|
$triggerBoot = New-ScheduledTaskTrigger -AtStartup
|
|
|
|
# Al doilea declansator: reporneste procesul daca a murit, fara sa-l dubleze.
|
|
# -RepetitionDuration se lasa nespecificat intentionat: inseamna "la nesfarsit".
|
|
# [TimeSpan]::MaxValue, desi documentat pentru asta, e respins de Task Scheduler
|
|
# ("P99999999DT23H59M59S ... out of range").
|
|
$triggerRepeat = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) `
|
|
-RepetitionInterval (New-TimeSpan -Minutes 10)
|
|
|
|
$settings = New-ScheduledTaskSettingsSet `
|
|
-AllowStartIfOnBatteries `
|
|
-DontStopIfGoingOnBatteries `
|
|
-StartWhenAvailable `
|
|
-MultipleInstances IgnoreNew `
|
|
-ExecutionTimeLimit ([TimeSpan]::Zero) `
|
|
-RestartCount 999 `
|
|
-RestartInterval (New-TimeSpan -Minutes 1)
|
|
|
|
$taskPrincipal = New-ScheduledTaskPrincipal -UserId 'NT AUTHORITY\SYSTEM' -LogonType ServiceAccount -RunLevel Highest
|
|
|
|
if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
|
|
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
|
|
}
|
|
|
|
Register-ScheduledTask -TaskName $TaskName `
|
|
-Description 'Monitorizeaza UPS-ul prin canalul HID nativ, alerteaza pe email si opreste curat Oracle inainte de epuizarea bateriei. Inlocuieste ViewPower.' `
|
|
-Action $action -Trigger @($triggerBoot, $triggerRepeat) `
|
|
-Settings $settings -Principal $taskPrincipal | Out-Null
|
|
|
|
Start-ScheduledTask -TaskName $TaskName
|
|
Start-Sleep -Seconds 5
|
|
|
|
Write-Host ''
|
|
Write-Host '--- rezultat ---'
|
|
Get-ScheduledTask -TaskName $TaskName | Format-Table -AutoSize TaskName, State
|
|
Get-ScheduledTaskInfo -TaskName $TaskName | Format-List LastRunTime, LastTaskResult, NumberOfMissedRuns
|
|
Write-Host ''
|
|
Write-Host 'Verificari utile:'
|
|
Write-Host (" powershell -ExecutionPolicy Bypass -File {0}\ups-monitor.ps1 -Mode Status" -f $InstallDir)
|
|
Write-Host (" powershell -ExecutionPolicy Bypass -File {0}\ups-monitor.ps1 -Mode TestMail" -f $InstallDir)
|
|
Write-Host (" powershell -ExecutionPolicy Bypass -File {0}\ups-monitor.ps1 -Mode TestShutdown" -f $InstallDir)
|
|
Write-Host ''
|
|
Write-Host ("Oprire de urgenta a automatismului: New-Item -ItemType File '{0}\DEZACTIVAT'" -f $InstallDir)
|