# check_dropbox_health.ps1 - watchdog per il client Dropbox (MSIX) su Ufficio. # # Dropbox.exe (pacchetto MSIX DropboxInc.Dropbox) va periodicamente in stato # "Not Responding" (osservato ricorrente da giugno 2026, su versioni diverse # del pacchetto - nessuna causa isolata trovata, vedi indagine 04/09/2026). # Questo script rileva l'hang e lo risolve con lo stesso ciclo verificato # manualmente: kill di tutti i processi Dropbox.exe, rilancio via # shell:AppsFolder (un'app MSIX non riparte in modo affidabile per # invocazione diretta dell'exe), verifica che sia tornata "Responding". # # Se Dropbox non risulta in esecuzione affatto (nessun processo Dropbox.exe), # lo script si limita a segnalarlo - non e' lo scenario per cui e' stato # scritto (l'utente potrebbe averla chiusa deliberatamente), nessuna azione. # # ESTESO 07/09/2026 (incidente reale, vedi archivio/Adrian/progetti/ # project_bridge_mailbox_gemello_ufficio.md): il controllo Responding=True # NON rileva un sync fermo - un processo puo' rispondere perfettamente alle # finestre e non sincronizzare comunque nulla. Quella sera lo stallo e' # durato 40+ minuti senza nessun alert, proprio perche' questo script # segnalava "sano" in continuazione. Aggiunto un secondo controllo, # indipendente dal primo: confronta la dimensione locale di # scripts/slave-mailbox/mailbox.log con la stessa via Z: (mount WebDAV verso # il disco vero su Nave, bypassa Dropbox per definizione) - se il locale # resta indietro oltre SYNC_STALL_THRESHOLD_SECONDS, segnala "sync fermo" # anche se Responding=True per tutti i processi, e tenta lo stesso ciclo di # kill+rilancio (l'incidente reale suggerisce che aiuti, anche se la causa # esatta non e' stata isolata). Scelto mailbox.log come canary perche' gia' # riceve scritture periodiche naturali (ogni job gate-ufficio completato, # ogni messaggio Adrian) - nessun meccanismo nuovo da mantenere altrove. # Stato (ultimo timestamp di stallo visto) persistito in un file locale # accanto ai log, per riconoscere uno stallo che dura piu' di un singolo # giro di questo job (ogni 15 min) senza falsi allarmi su un giro isolato. # # Exit code: 0 = sano (nessuno dei due problemi, o hung/stallo risolto con # successo). 1 = hung o sync fermo, e il rilancio non ha risolto entro il # timeout interno. # # Nota encoding: file volutamente ASCII-puro (niente em-dash/apostrofi # tipografici) - PowerShell 5.1 (powershell.exe, non pwsh) puo' misleggere # UTF-8 senza BOM e corrompere il parsing su caratteri speciali. $ErrorActionPreference = "Stop" function Write-Log($msg) { Write-Host "[check_dropbox_health] $msg" } # --- Controllo scarto di sync (locale vs Z:), indipendente da Responding --- $SyncStallThresholdSeconds = 1200 # 20 min: piu' di un giro di questo job (15 min), # evita falsi allarmi su un singolo giro in ritardo $DropboxRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..\..")).Path $ZRoot = "Z:\Dropbox\adrian" $CanaryRelPath = "scripts\slave-mailbox\mailbox.log" $StallStateFile = Join-Path $PSScriptRoot "..\logs\dropbox_sync_stall_since.txt" function Get-FileSizeOrZero($path) { if (Test-Path $path) { return (Get-Item $path).Length } return 0 } function Test-SyncStalled { $localPath = Join-Path $DropboxRoot $CanaryRelPath $zPath = Join-Path $ZRoot $CanaryRelPath if (-not (Test-Path $zPath)) { Write-Log "Sync check: Z: non raggiungibile ($zPath) - salto il controllo di scarto, nessun falso allarme." Remove-Item $StallStateFile -ErrorAction SilentlyContinue return $false } $localSize = Get-FileSizeOrZero $localPath $zSize = Get-FileSizeOrZero $zPath if ($zSize -le $localSize) { Write-Log "Sync check: locale ($localSize B) al passo con Z: ($zSize B)." Remove-Item $StallStateFile -ErrorAction SilentlyContinue return $false } $now = Get-Date if (Test-Path $StallStateFile) { $stallSince = Get-Content $StallStateFile -Raw | ForEach-Object { [DateTime]::Parse($_.Trim()) } } else { $stallSince = $now $now.ToString("o") | Set-Content $StallStateFile } $elapsed = ($now - $stallSince).TotalSeconds Write-Log "Sync check: locale ($localSize B) indietro rispetto a Z: ($zSize B) da $([math]::Round($elapsed))s." if ($elapsed -ge $SyncStallThresholdSeconds) { Write-Log "Sync check: soglia di $SyncStallThresholdSeconds s superata - sync considerato fermo." return $true } return $false } $syncStalled = Test-SyncStalled $procs = Get-Process -Name "Dropbox" -ErrorAction SilentlyContinue if (-not $procs) { Write-Log "Nessun processo Dropbox.exe in esecuzione - nessuna azione (fuori scope di questo watchdog)." exit 0 } # MainWindowTitle si e' rivelato inaffidabile per identificare il processo # "principale" (vuoto per tutti i processi Dropbox anche a app sana, diverso # da quanto mostra tasklist /V - verificato 04/09/2026). .Responding invece # e' significativo su qualunque processo: uno senza finestra/message loop # risulta sempre Responding=True per definizione, quindi basta controllare # se ALMENO UNO dei processi Dropbox.exe risulta Responding=False. $mainProc = $procs | Sort-Object WorkingSet64 -Descending | Select-Object -First 1 Write-Log "Processo principale (per memoria): PID $($mainProc.Id), $([math]::Round($mainProc.WorkingSet64/1MB,1))MB" $hung = $procs | Where-Object { -not $_.Responding } if ((-not $hung) -and (-not $syncStalled)) { Write-Log "Dropbox sano (tutti i $($procs.Count) processi Responding=True, sync al passo). Nessuna azione." exit 0 } if ($hung) { Write-Log "Dropbox in stato Not Responding (PID non responsivi: $($hung.Id -join ', ')) - avvio ciclo di recovery." } else { Write-Log "Dropbox Responding=True su tutti i processi, ma sync fermo da oltre $SyncStallThresholdSeconds s - avvio comunque il ciclo di recovery (incidente 07/09: il rilancio ha coinciso con la ripresa del sync, causa esatta non isolata, ma e' l'unica azione correttiva nota)." } Write-Log "Path eseguibile principale: $($mainProc.Path)" Stop-Process -Name "Dropbox" -Force -ErrorAction SilentlyContinue Write-Log "taskkill completato su tutti i processi Dropbox.exe." $app = Get-StartApps | Where-Object { $_.Name -eq "Dropbox" -and $_.AppID -like "*!*" } | Select-Object -First 1 if (-not $app) { Write-Log "ERRORE: AppID di Dropbox non trovato via Get-StartApps - impossibile rilanciare." exit 1 } Write-Log "AppID trovato: $($app.AppID)" Start-Process "explorer.exe" -ArgumentList "shell:AppsFolder\$($app.AppID)" Write-Log "Rilancio avviato, attendo 20s prima di verificare..." Start-Sleep -Seconds 20 $newProcs = Get-Process -Name "Dropbox" -ErrorAction SilentlyContinue if (-not $newProcs) { Write-Log "ERRORE: nessun processo Dropbox trovato dopo il rilancio." exit 1 } $newMain = $newProcs | Sort-Object WorkingSet64 -Descending | Select-Object -First 1 $newHung = $newProcs | Where-Object { -not $_.Responding } $newSyncStalled = Test-SyncStalled if ((-not $newHung) -and (-not $newSyncStalled)) { $memMB = [math]::Round($newMain.WorkingSet64 / 1MB, 1) Write-Log "Recovery riuscito: $($newProcs.Count) processi attivi, tutti Responding=True, sync al passo, principale PID $($newMain.Id) (${memMB}MB)." exit 0 } else { if ($newHung) { Write-Log "ATTENZIONE: dopo il rilancio, PID ancora non responsivi: $($newHung.Id -join ', ')." } if ($newSyncStalled) { Write-Log "ATTENZIONE: dopo il rilancio, il sync risulta ancora fermo - potrebbe servire piu' tempo del timeout di questo job (20s) o un intervento manuale." } exit 1 }