# =============================================================================
# Diagnostica Windows - Strumento avanzato con GUI WPF
# Compatibile con Windows 10 e Windows 11
#
# Avvio rapido (da PowerShell normale, non serve admin):
# irm https://get.23022.it | iex
#
# Lo script si auto-eleva via UAC e si rilancia con -ExecutionPolicy Bypass
# Nessuna modifica permanente al sistema (eccetto reset rete su richiesta)
# =============================================================================
# ---- Auto-bootstrap: garantisce admin + STA + Bypass policy ----------------
$ScriptUrl = 'https://get.23022.it'
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)
$isStaThread = ([Threading.Thread]::CurrentThread.GetApartmentState() -eq 'STA')
if (-not $isAdmin -or -not $isStaThread) {
Write-Host ""
Write-Host " Diagnostica Windows" -ForegroundColor Cyan
if (-not $isAdmin) {
Write-Host " Richiesta elevazione amministratore via UAC..." -ForegroundColor Gray
} else {
Write-Host " Riavvio in modalita STA (richiesto per WPF)..." -ForegroundColor Gray
}
Write-Host ""
$tempPath = Join-Path $env:TEMP ("Diagnostica-Windows-{0}.ps1" -f ([Guid]::NewGuid().ToString('N').Substring(0,8)))
try {
$oldTls = [Net.ServicePointManager]::SecurityProtocol
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-RestMethod -Uri $ScriptUrl -OutFile $tempPath -UseBasicParsing -ErrorAction Stop
[Net.ServicePointManager]::SecurityProtocol = $oldTls
} catch {
Write-Host (" Impossibile scaricare lo script da " + $ScriptUrl) -ForegroundColor Red
Write-Host (" " + $_.Exception.Message) -ForegroundColor Red
Write-Host ""
Read-Host "Premi INVIO per chiudere"
return
}
$argList = @(
'-NoProfile'
'-ExecutionPolicy', 'Bypass'
'-STA'
'-WindowStyle', 'Hidden'
'-File', ('"' + $tempPath + '"')
)
try {
if (-not $isAdmin) {
Start-Process -FilePath 'powershell.exe' -ArgumentList $argList -Verb RunAs -ErrorAction Stop
} else {
Start-Process -FilePath 'powershell.exe' -ArgumentList $argList -ErrorAction Stop
}
} catch {
Write-Host " Elevazione annullata dall'utente." -ForegroundColor Yellow
}
return
}
# ----------------------------------------------------------------------------
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Windows.Forms
# -----------------------------------------------------------------------------
# XAML - definizione interfaccia
# -----------------------------------------------------------------------------
[xml]$xaml = @'
Pronto.
Seleziona uno strumento dalla barra laterale per iniziare, oppure clicca DIAGNOSTICA COMPLETA per eseguire tutte le verifiche.
'@
# -----------------------------------------------------------------------------
# Carica XAML e bind controlli
# -----------------------------------------------------------------------------
$reader = New-Object System.Xml.XmlNodeReader $xaml
$window = [Windows.Markup.XamlReader]::Load($reader)
$ctrl = @{}
foreach ($name in @(
'TitleBar','BtnMinimize','BtnMaximize','BtnClose',
'BtnSysInfo','BtnSFC','BtnDISM','BtnCHKDSK','BtnEvents','BtnDrivers','BtnPerf',
'BtnNetFull','BtnNetConfig','BtnPing','BtnDNS','BtnMTU','BtnTrace','BtnWiFi','BtnPorts','BtnTTFB','BtnAntivirus',
'BtnDisk','BtnMemory','BtnGPU','BtnBattery',
'BtnFlushDNS','BtnCleanTemp','BtnResetNet',
'BtnRunAll','BtnStop','BtnSave','BtnClear',
'LblTitle','LblSubtitle','LblStatus','Progress','OutputBox',
'LogoSmall','LogoFallback','LogoBig'
)) {
$ctrl[$name] = $window.FindName($name)
}
# -----------------------------------------------------------------------------
# Caricamento logo (file locale o base64 embedded da Deploy.ps1)
# -----------------------------------------------------------------------------
$LogoBase64 = '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' # Sostituito da Deploy.ps1
function Get-LogoBitmap {
if ($LogoBase64 -and $LogoBase64 -ne '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') {
try {
$bytes = [Convert]::FromBase64String($LogoBase64)
$ms = New-Object IO.MemoryStream(,$bytes)
$bmp = New-Object Windows.Media.Imaging.BitmapImage
$bmp.BeginInit()
$bmp.CacheOption = 'OnLoad'
$bmp.StreamSource = $ms
$bmp.EndInit()
$bmp.Freeze()
return $bmp
} catch {}
}
if ($PSScriptRoot) {
$local = Join-Path $PSScriptRoot 'logo.png'
if (Test-Path $local) {
try {
$bmp = New-Object Windows.Media.Imaging.BitmapImage
$bmp.BeginInit()
$bmp.CacheOption = 'OnLoad'
$bmp.UriSource = [Uri]$local
$bmp.EndInit()
$bmp.Freeze()
return $bmp
} catch {}
}
}
return $null
}
$logoImg = Get-LogoBitmap
if ($logoImg) {
$ctrl.LogoSmall.Source = $logoImg
$ctrl.LogoBig.Source = $logoImg
} else {
# Fallback: pallino blu + nasconde le Image
$ctrl.LogoSmall.Visibility = 'Collapsed'
$ctrl.LogoFallback.Visibility = 'Visible'
}
# -----------------------------------------------------------------------------
# Stato condiviso (UI <-> Runspace)
# -----------------------------------------------------------------------------
$script:syncHash = [hashtable]::Synchronized(@{})
$script:syncHash.Window = $window
$script:syncHash.OutputBox = $ctrl.OutputBox
$script:syncHash.LblStatus = $ctrl.LblStatus
$script:syncHash.Progress = $ctrl.Progress
$script:syncHash.Stop = $false
$script:syncHash.Running = $false
$script:runspace = $null
$script:psInstance = $null
$script:asyncResult = $null
# -----------------------------------------------------------------------------
# Info diagnostiche (titolo, sottotitolo, descrizione dettagliata, rischio)
# -----------------------------------------------------------------------------
$diagInfo = @{}
$diagInfo['sysinfo'] = @{
Title='Info sistema'; Subtitle='OS, hardware, uptime e versione di Windows.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Raccoglie informazioni di base sul sistema:',
' * Versione, edizione, build di Windows',
' * Produttore, modello, BIOS',
' * RAM totale, hostname, utente attivo',
' * Uptime dall ultimo riavvio',
'',
'Solo lettura: nessuna modifica al sistema.'
)
}
$diagInfo['sfc'] = @{
Title='SFC - Verifica integrita file'; Subtitle='System File Checker - ripara file di sistema corrotti.'
Time='5-15 minuti'; Risk='moderato'
Detail=@(
'Esegue "sfc /scannow":',
' * Verifica tutti i file di sistema protetti',
' * Confronta versioni con il catalog Windows',
' * Ripara file danneggiati dalla cache locale',
'',
'Quando serve:',
' - Errori casuali del sistema o di Esplora risorse',
' - Crash, blocchi, schermate blu',
' - Dopo uno spegnimento improvviso',
'',
'Sicurezza: modifica SOLO file di sistema corrotti.',
'Non tocca dati utente, programmi o registro.'
)
}
$diagInfo['dism'] = @{
Title='DISM - Riparazione immagine Windows'; Subtitle='Verifica e ripara il component store di Windows.'
Time='10-25 minuti'; Risk='moderato'
Detail=@(
'Esegue tre fasi in sequenza:',
' 1) DISM /CheckHealth - verifica rapida problemi noti',
' 2) DISM /ScanHealth - scansione approfondita',
' 3) DISM /RestoreHealth - ripristina componenti danneggiati',
'',
'Quando serve:',
' - SFC trova errori che non riesce a riparare',
' - Aggiornamenti di Windows che falliscono',
' - Sistema instabile dopo update problematici',
'',
'Richiede connessione internet per scaricare i file di ripristino.'
)
}
$diagInfo['chkdsk'] = @{
Title='CHKDSK - Verifica disco'; Subtitle='Analisi read-only del disco di sistema.'
Time='2-10 minuti'; Risk='sicuro'
Detail=@(
'Esegue "chkdsk C:" in SOLA LETTURA:',
' * Verifica errori del file system NTFS',
' * Controlla settori danneggiati nei metadati',
' * NON modifica nulla sul disco',
'',
'Per riparare gli errori trovati serve "chkdsk /F" che richiede',
'un riavvio: non incluso qui per sicurezza.'
)
}
$diagInfo['events'] = @{
Title='Errori recenti (Event Log)'; Subtitle='Estrae errori critici delle ultime 48 ore.'
Time='~10 secondi'; Risk='sicuro'
Detail=@(
'Legge i Windows Event Logs di:',
' * Log Sistema (kernel, driver, servizi)',
' * Log Applicazioni (software installato)',
'',
'Filtra solo eventi di Livello 1 (Critico) e 2 (Errore)',
'nelle ultime 48 ore.',
'',
'Mostra fonte, ID, timestamp e prima riga del messaggio.',
'Utile per identificare la causa di crash o blocchi recenti.'
)
}
$diagInfo['drivers'] = @{
Title='Driver e periferiche'; Subtitle='Periferiche con errori e driver installati.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Esegue query WMI per:',
' * Trovare periferiche con codici errore (punto esclamativo)',
' * Elencare i driver firmati piu importanti',
' * Mostrare versione e produttore di ogni driver',
'',
'Utile per identificare hardware non funzionante.'
)
}
$diagInfo['perf'] = @{
Title='Prestazioni e processi'; Subtitle='Uso CPU/RAM, top processi attivi, avvio automatico.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Mostra:',
' * Carico CPU medio e percentuale RAM in uso',
' * Top 10 processi per uso CPU',
' * Top 10 processi per uso RAM',
' * Programmi che partono allavvio del PC',
'',
'Utile per identificare bloatware o processi sospetti.'
)
}
$diagInfo['netconfig'] = @{
Title='Configurazione IP'; Subtitle='Adattatori attivi, IP, gateway, DNS.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Mostra:',
' * Tutti gli adattatori di rete attivi',
' * Velocita link (Mbps), MAC address, stato media',
' * Indirizzi IPv4 e IPv6 assegnati',
' * Gateway predefinito e DNS in uso',
' * Output completo di "ipconfig /all"'
)
}
$diagInfo['ping'] = @{
Title='Test ping multi-target'; Subtitle='Verifica raggiungibilita gateway e internet.'
Time='~30 secondi'; Risk='sicuro'
Detail=@(
'Esegue 4 ping verso:',
' * Gateway LAN (router locale)',
' * Google DNS (8.8.8.8)',
' * Cloudflare DNS (1.1.1.1)',
' * Quad9 DNS (9.9.9.9)',
' * google.com',
' * microsoft.com',
'',
'Per ogni target: min/medio/max ms e pacchetti persi.',
'Identifica subito se il problema e LAN o internet.'
)
}
$diagInfo['dns'] = @{
Title='DNS - Test e benchmark'; Subtitle='Confronta tempi di risposta tra 5 server DNS.'
Time='~30 secondi'; Risk='sicuro'
Detail=@(
'Testa la risoluzione di 5 domini su 5 server DNS:',
' * DNS configurato sul sistema',
' * Google (8.8.8.8)',
' * Cloudflare (1.1.1.1)',
' * Quad9 (9.9.9.9)',
' * OpenDNS (208.67.222.222)',
'',
'Svuota la cache DNS prima di ogni test (misure pulite).',
'Se un DNS pubblico e molto piu veloce del tuo, suggerisce',
'di cambiare.'
)
}
$diagInfo['mtu'] = @{
Title='MTU - Scoperta automatica'; Subtitle='Calcola la MTU ottimale verso internet.'
Time='~20 secondi'; Risk='sicuro'
Detail=@(
'Usa "ping -f -l " con ricerca binaria per trovare',
'la dimensione massima di pacchetto senza frammentazione.',
'',
'Interpretazione:',
' * 1500 = ethernet standard (FTTH, fibra)',
' * 1492 = PPPoE tipico ADSL/FTTH',
' * <1450 = VPN attiva o doppio NAT',
'',
'MTU bassa = problemi con download grandi o timeout.'
)
}
$diagInfo['trace'] = @{
Title='Traceroute'; Subtitle='Percorso di rete verso 3 destinazioni.'
Time='~1 minuto'; Risk='sicuro'
Detail=@(
'Traceroute custom basato su .NET Ping (1 probe per hop,',
'3x piu veloce del tracert.exe nativo).',
'',
'Destinazioni: 8.8.8.8, 1.1.1.1, google.com',
'Max 18 hop, timeout 1.2 secondi per hop.',
'',
'Identifica il punto della rete dove si verifica il problema',
'(LAN, ISP, internet).'
)
}
$diagInfo['wifi'] = @{
Title='Wi-Fi e profili wireless'; Subtitle='Stato, profili salvati, driver wireless.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Esegue "netsh wlan" per mostrare:',
' * Interfacce Wi-Fi attive con SSID e segnale',
' * Tutti i profili Wi-Fi salvati sul PC',
' * Driver wireless installato e capabilities'
)
}
$diagInfo['ports'] = @{
Title='Porte e connessioni'; Subtitle='Porte in ascolto, connessioni attive, top app.'
Time='~10 secondi'; Risk='sicuro'
Detail=@(
'Mostra:',
' * Porte LISTENING con processo associato',
' * Connessioni TCP ESTABLISHED',
' * Test connettivita su porte comuni (HTTP/HTTPS/SMTP/IMAPS)',
' * Top 5 processi per connessioni TCP attive'
)
}
$diagInfo['ttfb'] = @{
Title='TTFB - Tempo risposta web'; Subtitle='Time-To-First-Byte verso 7 siti popolari.'
Time='~30 secondi'; Risk='sicuro'
Detail=@(
'Effettua richieste HTTPS HEAD verso:',
' google.com, microsoft.com, github.com,',
' cloudflare.com, amazon.it, repubblica.it, youtube.com',
'',
'Soglie:',
' < 500 ms -> ottimo',
' < 1500 ms -> accettabile',
' > 1500 ms -> navigazione lenta',
'',
'Indicatore reale della velocita percepita nel browsing.'
)
}
$diagInfo['antivirus'] = @{
Title='Antivirus e HTTPS scanning'; Subtitle='Rileva AV terzi che intercettano il traffico HTTPS.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Verifica:',
' * Antivirus registrati in WMI SecurityCenter',
' * Processi attivi di 18 antivirus noti',
' (Avast, AVG, Kaspersky, Bitdefender, ESET, McAfee,',
' Norton, Trend, Sophos, F-Secure, Malwarebytes, ecc.)',
' * Stato di Windows Defender (firme, real-time)',
'',
'Se hai un AV terzo e la navigazione e lenta, disattivare la',
'"scansione HTTPS/SSL" risolve nel 80% dei casi.'
)
}
$diagInfo['netfull'] = @{
Title='Diagnostica rete completa'; Subtitle='Tutti i test di rete in sequenza.'
Time='3-5 minuti'; Risk='sicuro'
Detail=@(
'Esegue in sequenza:',
' 1) IP pubblico + geolocalizzazione',
' 2) Configurazione IP completa',
' 3) Test ping multi-target',
' 4) Benchmark DNS (5 server)',
' 5) Scoperta MTU automatica',
' 6) Traceroute (3 destinazioni)',
' 7) Porte e connessioni',
' 8) TTFB HTTPS (7 siti)',
' 9) Rilevamento antivirus HTTPS scan',
'',
'La diagnostica piu completa per problemi di internet/rete.'
)
}
$diagInfo['disk'] = @{
Title='Dischi e stato SMART'; Subtitle='Spazio libero, SMART, cartelle temporanee.'
Time='~10 secondi'; Risk='sicuro'
Detail=@(
'Mostra:',
' * Tutte le unita logiche con spazio libero',
' * Dischi fisici con stato SMART (Healthy/Unhealthy)',
' * Dimensione cartelle TEMP e SoftwareDistribution',
'',
'SMART Unhealthy = il disco sta morendo, fai backup subito.'
)
}
$diagInfo['memory'] = @{
Title='Memoria RAM'; Subtitle='Moduli installati, utilizzo, file di paging.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Mostra:',
' * Ogni slot RAM: capacita, MHz, produttore, part-number',
' * RAM totale/libera/in uso',
' * Configurazione del file di paging',
'',
'Utile per planning upgrade RAM.'
)
}
$diagInfo['gpu'] = @{
Title='GPU - Scheda video'; Subtitle='Modello, driver, risoluzione corrente.'
Time='~3 secondi'; Risk='sicuro'
Detail=@(
'Per ogni GPU installata mostra:',
' * Nome e versione driver',
' * Data del driver (per capire se e obsoleto)',
' * Risoluzione e refresh rate attuale',
' * VRAM disponibile'
)
}
$diagInfo['battery'] = @{
Title='Batteria (laptop)'; Subtitle='Stato + report HTML dettagliato sul Desktop.'
Time='~5 secondi'; Risk='sicuro'
Detail=@(
'Per dispositivi con batteria:',
' * Livello carica e stato',
' * Tempo residuo stimato',
' * Tipo (Li-Ion, ecc.)',
'',
'Genera anche un report HTML completo via "powercfg /batteryreport"',
'sul Desktop, che mostra capacita di design vs capacita attuale',
'(degrado), cicli di carica, storico utilizzo.'
)
}
$diagInfo['flushdns'] = @{
Title='Pulizia cache DNS'; Subtitle='ipconfig /flushdns - operazione istantanea.'
Time='Istantaneo'; Risk='sicuro'
Detail=@(
'Svuota la cache DNS locale di Windows.',
'',
'Quando serve:',
' - Hai cambiato i DNS e i vecchi sembrano incollati',
' - Un sito non si apre ma da altri PC funziona',
' - Dopo aver modificato il file hosts',
'',
'Sicurezza totale, fatta da milioni di utenti ogni giorno.'
)
}
$diagInfo['cleantemp'] = @{
Title='Pulizia file temporanei'; Subtitle='Elimina TEMP utente, TEMP sistema, Prefetch.'
Time='1-3 minuti'; Risk='moderato'
Confirm=$true
ConfirmMessage="Verranno eliminati i file dalle cartelle TEMP utente, TEMP sistema e Prefetch.`n`nProcedere?"
Detail=@(
'Elimina file da:',
' * %TEMP% (cartella temp utente)',
' * C:\Windows\Temp (cartella temp sistema)',
' * C:\Windows\Prefetch (cache di avvio app)',
'',
'I file in uso vengono saltati automaticamente.',
'Nessun dato personale o documento viene toccato.',
'',
'Effetti positivi: libera spazio (spesso GB), risolve installer',
'che falliscono.',
'',
'Effetti collaterali minimi: i primi avvii di alcune app saranno',
'leggermente piu lenti (Prefetch viene ricostruito).'
)
}
$diagInfo['resetnet'] = @{
Title='Reset stack di rete'; Subtitle='Ripristina Winsock, TCP/IP, ARP, DHCP, DNS.'
Time='~30 secondi + RIAVVIO'; Risk='attenzione'
Confirm=$true
ConfirmMessage="ATTENZIONE: l operazione richiede il RIAVVIO del computer.`n`nVerranno resettati Winsock, TCP/IP e cache DNS.`n`nProcedere?"
Detail=@(
'Esegue in sequenza:',
' * netsh winsock reset (catalog Winsock di default)',
' * netsh int ip reset (stack TCP/IP)',
' * netsh interface ip delete arpcache',
' * ipconfig /release + /renew + /flushdns',
'',
'Quando serve:',
' - Internet non funziona inspiegabilmente',
' - Errori "DNS non risponde" persistenti',
' - Dopo disinstallazione di VPN/proxy/antivirus che',
' hanno lasciato residui',
'',
'IMPORTANTE:',
' - Verra richiesto di riavviare il PC alla fine',
' - Configurazioni VPN potrebbero richiedere ri-setup'
)
}
$diagInfo['full'] = @{
Title='Diagnostica completa'; Subtitle='Tutti i test non distruttivi in sequenza.'
Time='15-30 minuti'; Risk='sicuro'
Detail=@(
'Esegue in sequenza tutti i test non distruttivi:',
'',
' 1) Info sistema',
' 2) Prestazioni e processi',
' 3) Dischi e SMART',
' 4) Memoria RAM',
' 5) GPU',
' 6) Driver e periferiche',
' 7) Eventi del log Sistema/Applicazioni',
' 8) Diagnostica rete completa (9 sub-test)',
' 9) SFC - verifica integrita file',
' 10) DISM - riparazione immagine Windows',
' 11) CHKDSK - verifica disco (read-only)',
'',
'Le pulizie e i reset distruttivi NON sono inclusi:',
'vanno avviati manualmente dalla sidebar.'
)
}
# -----------------------------------------------------------------------------
# Funzioni gestione UI
# -----------------------------------------------------------------------------
$script:selectedDiag = $null
function Write-PreviewLine {
param([string]$Text, [string]$Color = '#C0CAF5')
$doc = $ctrl.OutputBox.Document
$last = $doc.Blocks | Select-Object -Last 1
if (-not $last) {
$last = New-Object Windows.Documents.Paragraph
$last.Margin = New-Object Windows.Thickness(0)
$doc.Blocks.Add($last)
}
$run = New-Object Windows.Documents.Run $Text
$run.Foreground = (New-Object Windows.Media.BrushConverter).ConvertFrom($Color)
$last.Inlines.Add($run)
$last.Inlines.Add((New-Object Windows.Documents.LineBreak))
}
function Show-Preview {
param([string]$Key)
if ($script:syncHash.Running) { return }
$info = $diagInfo[$Key]
if (-not $info) { return }
$script:selectedDiag = $Key
$ctrl.LblTitle.Text = $info.Title
$ctrl.LblSubtitle.Text = $info.Subtitle
$ctrl.OutputBox.Document.Blocks.Clear()
$p = New-Object Windows.Documents.Paragraph
$p.Margin = New-Object Windows.Thickness(0)
$ctrl.OutputBox.Document.Blocks.Add($p)
$riskColor = switch ($info.Risk) {
'sicuro' { '#9ECE6A' }
'moderato' { '#E0AF68' }
'attenzione' { '#F7768E' }
default { '#C0CAF5' }
}
Write-PreviewLine ''
Write-PreviewLine ('=' * 80) '#414868'
Write-PreviewLine (' ' + $info.Title) '#7AA2F7'
Write-PreviewLine ('=' * 80) '#414868'
Write-PreviewLine ''
Write-PreviewLine (' ' + $info.Subtitle) '#C0CAF5'
Write-PreviewLine ''
Write-PreviewLine (' Tempo stimato : ' + $info.Time) '#7DCFFF'
Write-PreviewLine (' Livello rischio : ' + $info.Risk) $riskColor
Write-PreviewLine ''
Write-PreviewLine ('-' * 80) '#292E42'
Write-PreviewLine ''
foreach ($line in $info.Detail) {
Write-PreviewLine (' ' + $line) '#C0CAF5'
}
Write-PreviewLine ''
Write-PreviewLine ('-' * 80) '#292E42'
Write-PreviewLine ''
if ($info.Risk -eq 'attenzione') {
Write-PreviewLine ' >>> Operazione SENSIBILE. Verra chiesta conferma prima di partire.' '#F7768E'
} else {
Write-PreviewLine ' >>> Clicca AVVIA in alto a destra per eseguire questa diagnostica.' '#BB9AF7'
}
Write-PreviewLine ''
# Aggiorna il pulsante Avvia
$shortTitle = ($info.Title -split ' - ')[0].ToUpper()
$ctrl.BtnRunAll.Content = "AVVIA: $shortTitle"
}
function Set-Header {
param([string]$Title, [string]$Subtitle)
$ctrl.LblTitle.Text = $Title
$ctrl.LblSubtitle.Text = $Subtitle
}
function Set-Running {
param([bool]$Running, [string]$StatusText = "")
$script:syncHash.Running = $Running
$ctrl.BtnStop.IsEnabled = $Running
foreach ($n in $ctrl.Keys) {
if ($n -like 'Btn*' -and $n -notin @('BtnStop','BtnSave','BtnClear','BtnMinimize','BtnMaximize','BtnClose')) {
$ctrl[$n].IsEnabled = -not $Running
}
}
if ($Running) {
$ctrl.Progress.IsIndeterminate = $true
$ctrl.LblStatus.Text = $StatusText
} else {
$ctrl.Progress.IsIndeterminate = $false
$ctrl.Progress.Value = if ($StatusText -like '*Interrotto*') { 0 } else { 100 }
$ctrl.LblStatus.Text = $StatusText
}
}
# -----------------------------------------------------------------------------
# Funzione output runspace (definita nel runspace)
# -----------------------------------------------------------------------------
$helpersBlock = @'
function W { param($T, $C = '#C0CAF5')
if ($null -eq $T) { $T = '' }
$text = "$T"
$color = $C
$sb = {
$doc = $syncHash.OutputBox.Document
$last = $doc.Blocks | Select-Object -Last 1
if (-not $last) {
$last = New-Object Windows.Documents.Paragraph
$last.Margin = New-Object Windows.Thickness(0)
$doc.Blocks.Add($last)
}
$run = New-Object Windows.Documents.Run $text
$run.Foreground = (New-Object Windows.Media.BrushConverter).ConvertFrom($color)
$last.Inlines.Add($run)
$last.Inlines.Add((New-Object Windows.Documents.LineBreak))
$syncHash.OutputBox.ScrollToEnd()
}.GetNewClosure()
$syncHash.Window.Dispatcher.Invoke([action]$sb) | Out-Null
}
function H1 { param($T)
W ''
W ('================================================================================') '#414868'
W (" $T") '#7AA2F7'
W ('================================================================================') '#414868'
}
function H2 { param($T)
W ''
W (">>> $T") '#BB9AF7'
W ('--------------------------------------------------------------------------------') '#292E42'
}
function OK { param($T) W "[OK] $T" '#9ECE6A' }
function WARN { param($T) W "[!] $T" '#E0AF68' }
function ERR { param($T) W "[X] $T" '#F7768E' }
function INFO { param($T) W " $T" '#C0CAF5' }
function DIM { param($T) W " $T" '#7DCFFF' }
function RAW { param($T) W "$T" '#565F89' }
function Status { param($T)
$msg = "$T"
$sb = { $syncHash.LblStatus.Text = $msg }.GetNewClosure()
$syncHash.Window.Dispatcher.Invoke([action]$sb) | Out-Null
}
function Should-Stop { return $syncHash.Stop }
function Run-Native {
param([string]$Cmd, [string[]]$Arguments)
$oReg = $null; $eReg = $null
try {
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $Cmd
$psi.Arguments = ($Arguments -join ' ')
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$psi.StandardOutputEncoding = [System.Text.Encoding]::UTF8
$psi.StandardErrorEncoding = [System.Text.Encoding]::UTF8
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $psi
$bag = [System.Collections.ArrayList]::Synchronized((New-Object System.Collections.ArrayList))
$handler = {
if (-not [string]::IsNullOrEmpty($EventArgs.Data)) {
[void]$Event.MessageData.Add($EventArgs.Data)
}
}
$oReg = Register-ObjectEvent -InputObject $proc -EventName OutputDataReceived -Action $handler -MessageData $bag
$eReg = Register-ObjectEvent -InputObject $proc -EventName ErrorDataReceived -Action $handler -MessageData $bag
[void]$proc.Start()
$proc.BeginOutputReadLine()
$proc.BeginErrorReadLine()
$idx = 0
while ((-not $proc.HasExited) -or ($idx -lt $bag.Count)) {
if ($syncHash.Stop -and -not $proc.HasExited) {
try { $proc.Kill() } catch {}
WARN 'Esecuzione interrotta.'
Start-Sleep -Milliseconds 200
}
while ($idx -lt $bag.Count) {
RAW $bag[$idx]
$idx++
}
if (-not $proc.HasExited) { Start-Sleep -Milliseconds 80 }
}
return $proc.ExitCode
} catch {
ERR ("Errore esecuzione $Cmd : " + $_.Exception.Message)
} finally {
if ($oReg) { Unregister-Event -SourceIdentifier $oReg.Name -ErrorAction SilentlyContinue }
if ($eReg) { Unregister-Event -SourceIdentifier $eReg.Name -ErrorAction SilentlyContinue }
}
}
'@
# -----------------------------------------------------------------------------
# Blocchi di diagnostica
# -----------------------------------------------------------------------------
$diagBlocks = @{}
# ----- INFO SISTEMA -----
$diagBlocks['sysinfo'] = @'
H1 "INFORMAZIONI SISTEMA"
Status 'Raccolta informazioni sistema...'
try {
$os = Get-CimInstance Win32_OperatingSystem
$cs = Get-CimInstance Win32_ComputerSystem
$bios = Get-CimInstance Win32_BIOS
H2 'Sistema operativo'
INFO ("Nome OS : " + $os.Caption)
INFO ("Versione : " + $os.Version + " (build " + $os.BuildNumber + ")")
INFO ("Architettura : " + $os.OSArchitecture)
INFO ("Installato il : " + $os.InstallDate)
INFO ("Ultimo boot : " + $os.LastBootUpTime)
$uptime = (Get-Date) - $os.LastBootUpTime
INFO ("Uptime : {0} giorni, {1} ore, {2} minuti" -f $uptime.Days, $uptime.Hours, $uptime.Minutes)
H2 'Hardware'
INFO ("Produttore : " + $cs.Manufacturer)
INFO ("Modello : " + $cs.Model)
INFO ("BIOS : " + $bios.Manufacturer + " " + $bios.SMBIOSBIOSVersion)
INFO ("Utente attivo : " + $cs.UserName)
INFO ("Hostname : " + $cs.Name)
INFO ("Dominio : " + $cs.Domain)
$totalRamGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
INFO ("RAM totale : $totalRamGB GB")
OK 'Informazioni sistema raccolte.'
} catch { ERR $_.Exception.Message }
'@
# ----- SFC -----
$diagBlocks['sfc'] = @'
H1 "SFC - SYSTEM FILE CHECKER"
W "Verifica integrita dei file di sistema Windows." '#7DCFFF'
W "Questa operazione puo richiedere 5-15 minuti." '#565F89'
W ''
Status 'Esecuzione sfc /scannow in corso...'
$ec = Run-Native -Cmd 'sfc.exe' -Arguments @('/scannow')
W ''
if ($ec -eq 0) { OK 'SFC completato senza errori.' }
elseif ($null -eq $ec) { WARN 'SFC interrotto.' }
else { WARN ("SFC terminato con codice: $ec") }
'@
# ----- DISM -----
$diagBlocks['dism'] = @'
H1 "DISM - DEPLOYMENT IMAGE SERVICING"
W "Verifica e ripara la salute dell immagine di Windows." '#7DCFFF'
W ''
H2 'DISM /Online /Cleanup-Image /CheckHealth'
Status 'DISM CheckHealth...'
Run-Native -Cmd 'DISM.exe' -Arguments @('/Online','/Cleanup-Image','/CheckHealth') | Out-Null
if (Should-Stop) { return }
H2 'DISM /Online /Cleanup-Image /ScanHealth'
Status 'DISM ScanHealth (puo richiedere alcuni minuti)...'
Run-Native -Cmd 'DISM.exe' -Arguments @('/Online','/Cleanup-Image','/ScanHealth') | Out-Null
if (Should-Stop) { return }
H2 'DISM /Online /Cleanup-Image /RestoreHealth'
Status 'DISM RestoreHealth (puo richiedere 10-20 minuti)...'
$ec = Run-Native -Cmd 'DISM.exe' -Arguments @('/Online','/Cleanup-Image','/RestoreHealth')
W ''
if ($ec -eq 0) { OK 'DISM RestoreHealth completato senza errori.' }
else { WARN ("DISM terminato con codice: $ec") }
'@
# ----- CHKDSK -----
$diagBlocks['chkdsk'] = @'
H1 "CHKDSK - VERIFICA FILE SYSTEM"
W "Modalita read-only: nessuna modifica al disco." '#7DCFFF'
W "Per riparare gli errori serve riavviare con chkdsk /F." '#565F89'
W ''
$drive = $env:SystemDrive
H2 ("Analisi disco $drive")
Status "CHKDSK $drive (read-only)..."
$ec = Run-Native -Cmd 'chkdsk.exe' -Arguments @($drive)
W ''
if ($ec -eq 0) { OK 'CHKDSK: nessun problema rilevato.' }
else { WARN ("CHKDSK terminato con codice: $ec (errori rilevati - pianifica chkdsk /F al riavvio)") }
'@
# ----- EVENT LOG ERRORS -----
$diagBlocks['events'] = @'
H1 "EVENT LOG - ERRORI RECENTI"
W "Estrazione errori critici dalle ultime 48 ore." '#7DCFFF'
$since = (Get-Date).AddHours(-48)
H2 "Sistema - Errori e critici (livello 1-2)"
Status 'Lettura log Sistema...'
try {
$sys = Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2; StartTime=$since} -MaxEvents 30 -ErrorAction Stop
if ($sys) {
foreach ($e in $sys) {
if (Should-Stop) { return }
$lvl = if ($e.Level -eq 1) {'CRIT'} else {'ERR '}
W ("[$lvl] " + $e.TimeCreated.ToString('dd/MM HH:mm') + " " + $e.ProviderName + " ID:" + $e.Id) '#F7768E'
$msg = ($e.Message -split "`n")[0]
if ($msg.Length -gt 140) { $msg = $msg.Substring(0,140) + '...' }
RAW (" " + $msg)
}
OK ("Trovati " + $sys.Count + " eventi nel log Sistema.")
} else {
OK 'Nessun errore critico nel log Sistema.'
}
} catch { WARN ("Impossibile leggere log Sistema: " + $_.Exception.Message) }
H2 "Applicazioni - Errori (livello 2)"
Status 'Lettura log Applicazioni...'
try {
$app = Get-WinEvent -FilterHashtable @{LogName='Application'; Level=1,2; StartTime=$since} -MaxEvents 20 -ErrorAction Stop
if ($app) {
foreach ($e in $app) {
if (Should-Stop) { return }
W ("[ERR ] " + $e.TimeCreated.ToString('dd/MM HH:mm') + " " + $e.ProviderName + " ID:" + $e.Id) '#E0AF68'
$msg = ($e.Message -split "`n")[0]
if ($msg.Length -gt 140) { $msg = $msg.Substring(0,140) + '...' }
RAW (" " + $msg)
}
OK ("Trovati " + $app.Count + " eventi nel log Applicazioni.")
} else {
OK 'Nessun errore critico nel log Applicazioni.'
}
} catch { WARN ("Impossibile leggere log Applicazioni: " + $_.Exception.Message) }
'@
# ----- DRIVERS -----
$diagBlocks['drivers'] = @'
H1 "DRIVER E PERIFERICHE"
Status 'Analisi periferiche...'
try {
$devs = Get-CimInstance Win32_PnPEntity | Where-Object { $_.ConfigManagerErrorCode -and $_.ConfigManagerErrorCode -ne 0 }
H2 'Periferiche con problemi'
if ($devs) {
foreach ($d in $devs) {
if (Should-Stop) { return }
ERR ($d.Name + " (codice errore: " + $d.ConfigManagerErrorCode + ")")
}
} else {
OK 'Nessuna periferica con problemi rilevati.'
}
H2 'Driver firmati (riepilogo)'
$drv = Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceName } | Select-Object -First 25
foreach ($d in $drv) {
RAW (" " + $d.DeviceName.PadRight(50).Substring(0,50) + " v" + $d.DriverVersion)
}
OK 'Analisi driver completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- PERFORMANCE -----
$diagBlocks['perf'] = @'
H1 "PRESTAZIONI E PROCESSI"
Status 'Lettura uso CPU e memoria...'
try {
H2 'Carico sistema'
$cpu = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
$os = Get-CimInstance Win32_OperatingSystem
$totMem = [math]::Round($os.TotalVisibleMemorySize/1MB, 2)
$freeMem = [math]::Round($os.FreePhysicalMemory/1MB, 2)
$usedPct = [math]::Round((($totMem-$freeMem)/$totMem)*100, 1)
INFO ("CPU media : $cpu %")
INFO ("RAM totale : $totMem GB")
INFO ("RAM libera : $freeMem GB")
INFO ("RAM utilizzata : $usedPct %")
H2 'Top 10 processi per CPU'
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | ForEach-Object {
$mem = [math]::Round($_.WorkingSet64/1MB, 1)
RAW (" " + $_.ProcessName.PadRight(30) + " CPU:" + ([string]([math]::Round($_.CPU,1))).PadLeft(8) + "s RAM:" + $mem + " MB")
}
H2 'Top 10 processi per RAM'
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 | ForEach-Object {
$mem = [math]::Round($_.WorkingSet64/1MB, 1)
RAW (" " + $_.ProcessName.PadRight(30) + " RAM:" + ($mem.ToString()).PadLeft(8) + " MB")
}
H2 'Programmi in avvio automatico'
$startup = Get-CimInstance Win32_StartupCommand
foreach ($s in $startup) {
RAW (" " + $s.Name.PadRight(35).Substring(0,[math]::Min(35,$s.Name.Length)) + " " + $s.Location)
}
OK 'Analisi prestazioni completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- NET CONFIG -----
$diagBlocks['netconfig'] = @'
H1 "CONFIGURAZIONE IP E ADATTATORI"
Status 'Analisi configurazione di rete...'
try {
H2 'Adattatori attivi'
Get-NetAdapter | Where-Object Status -eq 'Up' | ForEach-Object {
OK ($_.Name + " [" + $_.InterfaceDescription + "]")
INFO (" Velocita link : " + $_.LinkSpeed)
INFO (" Indirizzo MAC : " + $_.MacAddress)
INFO (" Stato media : " + $_.MediaConnectionState)
}
H2 'Configurazione IP'
Get-NetIPConfiguration | ForEach-Object {
if ($_.IPv4Address) {
INFO ($_.InterfaceAlias)
INFO (" IPv4 : " + ($_.IPv4Address.IPAddress -join ', '))
INFO (" Gateway IPv4 : " + ($_.IPv4DefaultGateway.NextHop -join ', '))
INFO (" DNS : " + ($_.DNSServer.ServerAddresses -join ', '))
INFO (" Profilo rete : " + $_.NetProfile.Name + " (" + $_.NetProfile.NetworkCategory + ")")
}
}
H2 'Output completo ipconfig /all'
Run-Native -Cmd 'ipconfig.exe' -Arguments @('/all') | Out-Null
OK 'Configurazione di rete completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- PING -----
$diagBlocks['ping'] = @'
H1 "TEST PING - CONNETTIVITA"
Status 'Test connettivita...'
try {
$gw = (Get-NetIPConfiguration | Where-Object { $_.IPv4DefaultGateway -ne $null } | Select-Object -First 1).IPv4DefaultGateway.NextHop
$targets = @()
if ($gw) { $targets += [pscustomobject]@{ Name = 'Gateway LAN'; Host = $gw } }
$targets += [pscustomobject]@{ Name = 'Google DNS'; Host = '8.8.8.8' }
$targets += [pscustomobject]@{ Name = 'Cloudflare DNS'; Host = '1.1.1.1' }
$targets += [pscustomobject]@{ Name = 'Quad9 DNS'; Host = '9.9.9.9' }
$targets += [pscustomobject]@{ Name = 'google.com'; Host = 'google.com' }
$targets += [pscustomobject]@{ Name = 'microsoft.com'; Host = 'microsoft.com' }
foreach ($t in $targets) {
if (Should-Stop) { return }
H2 ($t.Name + " -> " + $t.Host)
Status ("Ping verso " + $t.Host + "...")
try {
$r = Test-Connection -ComputerName $t.Host -Count 4 -ErrorAction Stop
$rtts = $r | ForEach-Object { $_.ResponseTime }
$avg = [math]::Round(($rtts | Measure-Object -Average).Average, 1)
$mn = ($rtts | Measure-Object -Minimum).Minimum
$mx = ($rtts | Measure-Object -Maximum).Maximum
$loss = 4 - $r.Count
OK ("Min: $mn ms Med: $avg ms Max: $mx ms Persi: $loss/4")
} catch {
ERR ("Host non raggiungibile: " + $t.Host)
}
}
OK 'Test ping completato.'
} catch { ERR $_.Exception.Message }
'@
# ----- DNS TEST -----
$diagBlocks['dns'] = @'
H1 "DNS - TEST E BENCHMARK"
W "Verifica risoluzione DNS e confronta tempi di risposta tra server." '#7DCFFF'
Status 'Test DNS in corso...'
$dnsServers = @(
@{ Name='Sistema (default)'; Ip=$null },
@{ Name='Google'; Ip='8.8.8.8' },
@{ Name='Cloudflare'; Ip='1.1.1.1' },
@{ Name='Quad9'; Ip='9.9.9.9' },
@{ Name='OpenDNS'; Ip='208.67.222.222' }
)
$testDomains = @('google.com','github.com','microsoft.com','cloudflare.com','wikipedia.org')
$dnsMedi = @{}
foreach ($srv in $dnsServers) {
if (Should-Stop) { return }
if ($srv.Ip) { H2 ("Server DNS: " + $srv.Name + " (" + $srv.Ip + ")") }
else { H2 ("Server DNS: " + $srv.Name) }
$totalMs = 0; $ok = 0
foreach ($d in $testDomains) {
if (Should-Stop) { return }
try {
Clear-DnsClientCache -ErrorAction SilentlyContinue
$sw = [System.Diagnostics.Stopwatch]::StartNew()
if ($srv.Ip) {
$res = Resolve-DnsName -Name $d -Server $srv.Ip -DnsOnly -NoHostsFile -Type A -ErrorAction Stop -QuickTimeout
} else {
$res = Resolve-DnsName -Name $d -DnsOnly -NoHostsFile -Type A -ErrorAction Stop -QuickTimeout
}
$sw.Stop()
$ms = $sw.ElapsedMilliseconds
$ip = ($res | Where-Object Type -eq 'A' | Select-Object -First 1).IPAddress
if (-not $ip) { $ip = '(no A)' }
$c = if ($ms -lt 100) {'#9ECE6A'} elseif ($ms -lt 500) {'#E0AF68'} else {'#F7768E'}
W (" " + $d.PadRight(20) + " -> " + $ip.PadRight(18) + " " + $ms + " ms") $c
$totalMs += $ms; $ok++
} catch {
ERR (" " + $d.PadRight(20) + " -> FALLITO")
}
}
if ($ok -gt 0) {
$avg = [math]::Round($totalMs/$ok, 1)
OK ("Media tempo risposta: $avg ms ($ok/$($testDomains.Count) risolti)")
$dnsMedi[$srv.Name] = $avg
} else {
ERR 'Nessuna risoluzione riuscita.'
}
}
H2 'Classifica DNS (dal piu veloce)'
$dnsMedi.GetEnumerator() | Sort-Object Value | ForEach-Object {
$c = if ($_.Value -lt 100) {'#9ECE6A'} elseif ($_.Value -lt 500) {'#E0AF68'} else {'#F7768E'}
W (" " + ($_.Name.PadRight(28)) + " " + $_.Value + " ms") $c
}
$confName = $dnsServers[0].Name
$confMedia = $dnsMedi[$confName]
if ($confMedia) {
$altri = $dnsMedi.GetEnumerator() | Where-Object { $_.Name -ne $confName } | Sort-Object Value | Select-Object -First 1
if ($altri -and $confMedia -gt ($altri.Value * 1.5)) {
WARN ("Il DNS '" + $altri.Name + "' e' molto piu' veloce del tuo (" + $altri.Value + " ms vs " + $confMedia + " ms). Valuta di cambiare.")
} else {
OK 'Il DNS configurato e in linea con i migliori pubblici.'
}
}
H2 'Verifica DNS leak'
try {
$publicDns = (Resolve-DnsName -Name 'whoami.akamai.net' -Type A -ErrorAction Stop -QuickTimeout)
if ($publicDns) {
INFO ("DNS pubblico in uscita: " + ($publicDns | Where-Object Type -eq 'A' | Select-Object -First 1).IPAddress)
}
} catch { WARN 'Impossibile determinare il DNS pubblico in uscita.' }
OK 'Test DNS completato.'
'@
# ----- MTU DISCOVERY -----
$diagBlocks['mtu'] = @'
H1 "MTU - SCOPERTA AUTOMATICA"
W "Trova la MTU massima verso 8.8.8.8 tramite ricerca binaria." '#7DCFFF'
W "MTU corretta = ultimo size + 28 byte (header IP+ICMP)." '#565F89'
Status 'Ricerca MTU in corso...'
$target = '8.8.8.8'
function Test-MtuSize { param([int]$size, [string]$tg)
$r = & ping.exe -n 1 -w 1500 -f -l $size $tg 2>$null
return ($r -match 'TTL=')
}
H2 'Test MTU per interfaccia attiva'
Get-NetAdapter | Where-Object Status -eq 'Up' | ForEach-Object {
INFO (" Interfaccia: " + $_.Name + " MTU configurata: " + $_.MtuSize)
}
H2 "Ricerca binaria verso $target"
$low = 1200
$high = 1500
$lastOk = 0
INFO 'Test rapido a 1472 (ethernet standard - 28)...'
if (Test-MtuSize -size 1472 -tg $target) {
OK ' 1472 OK -> MTU >= 1500'
$lastOk = 1472
} else {
WARN ' 1472 fallito -> MTU minore di 1500'
}
if ($lastOk -lt 1472) {
INFO 'Inizio ricerca binaria...'
while (($high - $low) -gt 1) {
if (Should-Stop) { return }
$mid = [math]::Floor(($low + $high) / 2)
Status "Test MTU size $mid..."
if (Test-MtuSize -size $mid -tg $target) {
DIM (" $mid : OK")
$low = $mid
$lastOk = $mid
} else {
DIM (" $mid : FRAGMENT")
$high = $mid
}
}
}
$mtu = $lastOk + 28
W ''
OK ("MTU ottimale stimata: $mtu byte (payload max: $lastOk)")
if ($mtu -ge 1500) { INFO 'MTU standard ethernet (1500). Connessione ottimale.' }
elseif ($mtu -ge 1492) { INFO 'MTU tipica PPPoE (1492). Connessione ADSL/FTTH con PPPoE.' }
elseif ($mtu -ge 1450) { WARN 'MTU ridotta. Potresti avere VPN o doppio NAT.' }
else { WARN 'MTU molto bassa. Verifica configurazione router/VPN.' }
'@
# ----- TRACEROUTE -----
$diagBlocks['trace'] = @'
H1 "TRACEROUTE - PERCORSO DI RETE"
W "Traceroute custom basato su .NET Ping (1 probe per hop)." '#7DCFFF'
W "Veloce e interrompibile in qualsiasi momento." '#565F89'
$targets = @('8.8.8.8','1.1.1.1','google.com')
$maxHops = 18
$timeoutMs = 1200
foreach ($t in $targets) {
if (Should-Stop) { return }
H2 ("Verso " + $t)
Status ("Traceroute verso " + $t + "...")
$ping = New-Object System.Net.NetworkInformation.Ping
$opts = New-Object System.Net.NetworkInformation.PingOptions(1, $false)
$bytes = [System.Text.Encoding]::ASCII.GetBytes(('X' * 32))
$reached = $false
for ($ttl = 1; $ttl -le $maxHops; $ttl++) {
if (Should-Stop) { $ping.Dispose(); return }
$opts.Ttl = $ttl
try {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
$reply = $ping.Send($t, $timeoutMs, $bytes, $opts)
$sw.Stop()
$ms = $sw.ElapsedMilliseconds
$addr = if ($reply -and $reply.Address) { $reply.Address.ToString() } else { '*' }
$stat = if ($reply) { $reply.Status.ToString() } else { 'NoReply' }
$line = (" hop {0,2} {1,5} ms {2,-18} [{3}]" -f $ttl, $ms, $addr, $stat)
if ($stat -eq 'Success') {
W $line '#9ECE6A'
$reached = $true
break
} elseif ($stat -eq 'TtlExpired') {
W $line '#7DCFFF'
} else {
W (" hop {0,2} ----- ms * [{1}]" -f $ttl, $stat) '#565F89'
}
} catch {
W (" hop {0,2} ----- ms * [errore]" -f $ttl) '#565F89'
}
}
try { $ping.Dispose() } catch {}
if (-not $reached) { WARN ("Destinazione non raggiunta entro $maxHops hop.") }
else { OK ("Destinazione raggiunta.") }
}
OK 'Traceroute completato.'
'@
# ----- WIFI -----
$diagBlocks['wifi'] = @'
H1 "WI-FI E PROFILI WIRELESS"
Status 'Analisi Wi-Fi...'
try {
H2 'Interfacce Wi-Fi'
Run-Native -Cmd 'netsh.exe' -Arguments @('wlan','show','interfaces') | Out-Null
if (Should-Stop) { return }
H2 'Profili Wi-Fi salvati'
Run-Native -Cmd 'netsh.exe' -Arguments @('wlan','show','profiles') | Out-Null
if (Should-Stop) { return }
H2 'Driver wireless'
Run-Native -Cmd 'netsh.exe' -Arguments @('wlan','show','drivers') | Out-Null
OK 'Analisi Wi-Fi completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- PORTS -----
$diagBlocks['ports'] = @'
H1 "PORTE E CONNESSIONI ATTIVE"
Status 'Analisi porte e connessioni...'
try {
H2 'Porte in ascolto (LISTENING)'
$listen = Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Sort-Object LocalPort -Unique
foreach ($c in $listen | Select-Object -First 30) {
if (Should-Stop) { return }
$proc = try { (Get-Process -Id $c.OwningProcess -ErrorAction Stop).ProcessName } catch { '?' }
RAW (" " + ($c.LocalAddress + ":" + $c.LocalPort).PadRight(28) + " " + $proc)
}
H2 'Connessioni stabilite'
$estab = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue | Select-Object -First 20
foreach ($c in $estab) {
if (Should-Stop) { return }
$proc = try { (Get-Process -Id $c.OwningProcess -ErrorAction Stop).ProcessName } catch { '?' }
RAW (" " + ($c.LocalAddress + ":" + $c.LocalPort).PadRight(28) + " -> " + ($c.RemoteAddress + ":" + $c.RemotePort).PadRight(28) + " " + $proc)
}
H2 'Test porte comuni in uscita'
$portTests = @(
@{ Host='google.com'; Port=80; Name='HTTP' },
@{ Host='google.com'; Port=443; Name='HTTPS' },
@{ Host='gmail.com'; Port=587; Name='SMTP' },
@{ Host='gmail.com'; Port=993; Name='IMAPS' }
)
foreach ($p in $portTests) {
if (Should-Stop) { return }
$r = Test-NetConnection -ComputerName $p.Host -Port $p.Port -InformationLevel Quiet -WarningAction SilentlyContinue
if ($r) { OK ($p.Name + " (" + $p.Host + ":" + $p.Port + ") aperta") }
else { ERR ($p.Name + " (" + $p.Host + ":" + $p.Port + ") bloccata") }
}
H2 'Top 5 processi per connessioni TCP attive'
$byProc = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
Group-Object -Property OwningProcess | Sort-Object Count -Descending | Select-Object -First 5
foreach ($g in $byProc) {
if (Should-Stop) { return }
$proc = try { Get-Process -Id $g.Name -ErrorAction Stop } catch { $null }
if ($proc) {
$name = $proc.ProcessName
INFO (" " + $name.PadRight(30).Substring(0,[math]::Min(30,$name.Length)) + " -> " + $g.Count + " connessioni attive")
}
}
OK 'Analisi porte completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- TTFB (TEMPO RISPOSTA WEB) -----
$diagBlocks['ttfb'] = @'
H1 "TTFB - TEMPO RISPOSTA SITI WEB (HTTPS)"
W "Misura il Time-To-First-Byte verso siti popolari." '#7DCFFF'
W "Indica la velocita reale percepita durante la navigazione." '#565F89'
Status 'Test TTFB in corso...'
$siti = @('google.com','microsoft.com','github.com','cloudflare.com','amazon.it','repubblica.it','youtube.com')
$tempi = @()
foreach ($d in $siti) {
if (Should-Stop) { return }
try {
$sw = [System.Diagnostics.Stopwatch]::StartNew()
$null = Invoke-WebRequest -Uri ("https://" + $d) -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
$sw.Stop()
$ms = [math]::Round($sw.ElapsedMilliseconds, 0)
$tempi += $ms
$c = if ($ms -lt 500) {'#9ECE6A'} elseif ($ms -lt 1500) {'#E0AF68'} else {'#F7768E'}
W (" " + $d.PadRight(28) + " " + ($ms.ToString().PadLeft(6)) + " ms") $c
} catch {
W (" " + $d.PadRight(28) + " TIMEOUT / ERRORE") '#F7768E'
}
}
W ''
if ($tempi.Count -gt 0) {
$avg = [math]::Round(($tempi | Measure-Object -Average).Average, 0)
$min = ($tempi | Measure-Object -Minimum).Minimum
$max = ($tempi | Measure-Object -Maximum).Maximum
INFO ("Min: $min ms Media: $avg ms Max: $max ms")
if ($avg -gt 1500) { ERR ("TTFB medio MOLTO alto: $avg ms - navigazione molto lenta") }
elseif ($avg -gt 700) { WARN ("TTFB medio alto: $avg ms - possibile congestione o DNS lento") }
else { OK ("TTFB medio buono: $avg ms") }
} else {
ERR 'Nessun sito raggiungibile.'
}
'@
# ----- ANTIVIRUS / HTTPS SCANNING -----
$diagBlocks['antivirus'] = @'
H1 "ANTIVIRUS E SCANSIONE HTTPS"
W "Gli antivirus di terze parti intercettano spesso il traffico HTTPS." '#7DCFFF'
W "Questo puo' rallentare drasticamente la navigazione." '#565F89'
Status 'Rilevamento antivirus...'
H2 'Software antivirus registrato in Windows Security Center'
try {
$av = Get-CimInstance -Namespace 'root/SecurityCenter2' -ClassName 'AntiVirusProduct' -ErrorAction Stop
foreach ($a in $av) {
$state = '0x{0:X}' -f $a.productState
INFO (" " + $a.displayName.PadRight(40) + " stato: " + $state + " path: " + $a.pathToSignedProductExe)
}
if (-not $av) { WARN 'Nessun antivirus registrato in WMI SecurityCenter.' }
} catch { WARN 'Impossibile leggere SecurityCenter (necessari privilegi admin).' }
H2 'Processi antivirus attivi (terze parti)'
$avList = @('avast','avg','kaspersky','bitdefender','eset','nod32','mcafee','norton','trend','sophos','f-secure','gdata','comodo','webroot','malwarebytes','panda','crowdstrike','sentinelone')
$procs = Get-Process -ErrorAction SilentlyContinue
$found = @()
foreach ($a in $avList) {
$match = $procs | Where-Object { $_.Name -match $a -or $_.Company -match $a }
if ($match) {
$found += $a
foreach ($m in $match | Select-Object -First 3) {
INFO (" " + $m.Name + " (" + $m.Company + ")")
}
}
}
W ''
if ($found.Count -gt 0) {
WARN ("Antivirus terzo rilevato: " + ($found -join ', '))
W " Se la navigazione e' lenta:" '#E0AF68'
W " 1. Apri il pannello dell'antivirus" '#C0CAF5'
W " 2. Disattiva temporaneamente 'protezione web' o 'scansione HTTPS/SSL'" '#C0CAF5'
W " 3. Ritesta TTFB e DNS per confrontare" '#C0CAF5'
} else {
OK 'Nessun antivirus terzo rilevato. Stai usando probabilmente solo Windows Defender.'
}
H2 'Windows Defender'
try {
$def = Get-MpComputerStatus -ErrorAction Stop
INFO ("Antivirus attivo : " + $def.AntivirusEnabled)
INFO ("Real-time prot. : " + $def.RealTimeProtectionEnabled)
INFO ("Versione firme : " + $def.AntivirusSignatureVersion)
INFO ("Ultimo aggiorn. : " + $def.AntivirusSignatureLastUpdated)
} catch { DIM 'Get-MpComputerStatus non disponibile.' }
'@
# ----- NET FULL (combina tutte le verifiche di rete) -----
$diagBlocks['netfull'] = @'
H1 "DIAGNOSTICA RETE COMPLETA"
W "Esecuzione sequenziale di tutti i test di rete." '#7DCFFF'
# Public IP test
H2 'IP pubblico e geolocalizzazione'
Status 'Recupero IP pubblico...'
try {
$ip = Invoke-RestMethod -Uri 'https://api.ipify.org?format=json' -TimeoutSec 6 -ErrorAction Stop
OK ("IP pubblico: " + $ip.ip)
try {
$geo = Invoke-RestMethod -Uri ("http://ip-api.com/json/" + $ip.ip + "?fields=country,regionName,city,isp,org") -TimeoutSec 6 -ErrorAction Stop
INFO ("Provider : " + $geo.isp)
INFO ("Organizz. : " + $geo.org)
INFO ("Posizione : " + $geo.city + ", " + $geo.regionName + ", " + $geo.country)
} catch { WARN 'Geolocalizzazione non disponibile.' }
} catch { ERR 'Impossibile contattare api.ipify.org' }
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['netconfig']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['ping']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['dns']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['mtu']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['trace']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['ports']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['ttfb']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['antivirus']))
if (Should-Stop) { return }
H1 'DIAGNOSTICA RETE COMPLETATA'
OK 'Tutti i test di rete sono stati eseguiti.'
'@
# ----- DISK -----
$diagBlocks['disk'] = @'
H1 "DISCHI E STATO SMART"
Status 'Analisi unita di archiviazione...'
try {
H2 'Unita logiche'
Get-Volume | Where-Object DriveLetter | ForEach-Object {
$size = if ($_.Size) { [math]::Round($_.Size/1GB,1) } else { 0 }
$free = if ($_.SizeRemaining) { [math]::Round($_.SizeRemaining/1GB,1) } else { 0 }
$pct = if ($_.Size -gt 0) { [math]::Round(($_.Size-$_.SizeRemaining)/$_.Size*100,1) } else { 0 }
$clr = if ($pct -gt 90) { '#F7768E' } elseif ($pct -gt 75) { '#E0AF68' } else { '#9ECE6A' }
W (" [" + $_.DriveLetter + ":] " + $_.FileSystemLabel.PadRight(20).Substring(0,[math]::Min(20,($_.FileSystemLabel + '').Length)) + " " + $free + " GB liberi su " + $size + " GB (uso $pct%)") $clr
}
H2 'Dischi fisici e SMART'
Get-PhysicalDisk | ForEach-Object {
$sz = [math]::Round($_.Size/1GB,1)
$hc = $_.HealthStatus
$op = $_.OperationalStatus
$clr = if ($hc -eq 'Healthy') { '#9ECE6A' } else { '#F7768E' }
W (" " + $_.FriendlyName.PadRight(40).Substring(0,[math]::Min(40,$_.FriendlyName.Length)) + " " + $_.MediaType.PadRight(8) + " " + $sz + " GB SMART: " + $hc + " Stato: " + $op) $clr
}
H2 'Dimensione cartelle temp'
$tempPaths = @($env:TEMP, "$env:WINDIR\Temp", "$env:WINDIR\SoftwareDistribution\Download")
foreach ($p in $tempPaths) {
if (Should-Stop) { return }
if (Test-Path $p) {
try {
$s = (Get-ChildItem $p -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
$mb = [math]::Round(($s/1MB),1)
INFO (" " + $p.PadRight(55).Substring(0,[math]::Min(55,$p.Length)) + " " + $mb + " MB")
} catch {}
}
}
OK 'Analisi disco completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- MEMORY -----
$diagBlocks['memory'] = @'
H1 "MEMORIA RAM"
Status 'Analisi memoria...'
try {
H2 'Moduli RAM installati'
Get-CimInstance Win32_PhysicalMemory | ForEach-Object {
$cap = [math]::Round($_.Capacity/1GB,1)
$sp = $_.ConfiguredClockSpeed
$man = $_.Manufacturer
$pn = $_.PartNumber
$loc = $_.DeviceLocator
INFO (" Slot " + $loc.PadRight(15) + " " + $cap + " GB " + $sp + " MHz " + $man.Trim() + " " + $pn.Trim())
}
H2 'Utilizzo attuale'
$os = Get-CimInstance Win32_OperatingSystem
$tot = [math]::Round($os.TotalVisibleMemorySize/1MB,2)
$free = [math]::Round($os.FreePhysicalMemory/1MB,2)
$used = [math]::Round($tot-$free,2)
$pct = [math]::Round(($used/$tot)*100,1)
INFO ("Totale : $tot GB")
INFO ("Libera : $free GB")
INFO ("In uso : $used GB ($pct%)")
H2 'File di paging'
Get-CimInstance Win32_PageFileUsage | ForEach-Object {
INFO (" " + $_.Name + " " + [math]::Round($_.AllocatedBaseSize) + " MB (uso corrente " + [math]::Round($_.CurrentUsage) + " MB)")
}
OK 'Analisi memoria completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- GPU -----
$diagBlocks['gpu'] = @'
H1 "GPU - SCHEDA GRAFICA"
Status 'Analisi GPU...'
try {
Get-CimInstance Win32_VideoController | ForEach-Object {
H2 ($_.Name)
$vram = if ($_.AdapterRAM) { [math]::Round($_.AdapterRAM/1GB,1) } else { 'n/d' }
INFO ("Driver : " + $_.DriverVersion)
INFO ("Data driver : " + $_.DriverDate)
INFO ("Risoluzione : " + $_.CurrentHorizontalResolution + "x" + $_.CurrentVerticalResolution + " @ " + $_.CurrentRefreshRate + "Hz")
INFO ("VRAM : $vram GB")
INFO ("Stato : " + $_.Status)
}
OK 'Analisi GPU completata.'
} catch { ERR $_.Exception.Message }
'@
# ----- BATTERY -----
$diagBlocks['battery'] = @'
H1 "BATTERIA (NOTEBOOK)"
Status 'Generazione report batteria...'
try {
$bat = Get-CimInstance Win32_Battery -ErrorAction SilentlyContinue
if (-not $bat) {
WARN 'Nessuna batteria rilevata (PC desktop?).'
return
}
$bat | ForEach-Object {
H2 ($_.Name)
INFO ("Livello carica : " + $_.EstimatedChargeRemaining + " %")
INFO ("Stato : " + $_.BatteryStatus)
INFO ("Tempo residuo : " + (if ($_.EstimatedRunTime -lt 71582788) { $_.EstimatedRunTime.ToString() + " min" } else { 'collegato a corrente' }))
INFO ("Tipo : " + $_.Chemistry)
}
H2 'Generazione report HTML dettagliato'
$outFile = Join-Path $env:USERPROFILE "Desktop\battery-report.html"
$ec = Run-Native -Cmd 'powercfg.exe' -Arguments @('/batteryreport', '/output', "`"$outFile`"")
if (Test-Path $outFile) {
OK ("Report salvato sul Desktop: " + $outFile)
}
} catch { ERR $_.Exception.Message }
'@
# ----- FLUSH DNS -----
$diagBlocks['flushdns'] = @'
H1 "PULIZIA CACHE DNS"
Status 'Pulizia cache DNS...'
$ec = Run-Native -Cmd 'ipconfig.exe' -Arguments @('/flushdns')
if ($ec -eq 0) { OK 'Cache DNS svuotata correttamente.' }
else { ERR 'Errore durante la pulizia della cache DNS.' }
'@
# ----- CLEAN TEMP -----
$diagBlocks['cleantemp'] = @'
H1 "PULIZIA FILE TEMPORANEI"
W "Vengono eliminati i file in TEMP utente, TEMP sistema e cache prefetch." '#7DCFFF'
$paths = @($env:TEMP, "$env:WINDIR\Temp", "$env:WINDIR\Prefetch")
$totalFreed = 0
foreach ($p in $paths) {
if (Should-Stop) { return }
H2 ("Pulizia: " + $p)
Status ("Pulizia $p...")
if (-not (Test-Path $p)) { WARN 'Percorso non trovato.'; continue }
$files = Get-ChildItem $p -Recurse -Force -ErrorAction SilentlyContinue
$sizeBefore = ($files | Measure-Object -Property Length -Sum).Sum
$deleted = 0; $skipped = 0
foreach ($f in $files) {
if (Should-Stop) { return }
try {
Remove-Item -LiteralPath $f.FullName -Force -Recurse -ErrorAction Stop
$deleted++
} catch { $skipped++ }
}
$filesAfter = Get-ChildItem $p -Recurse -Force -ErrorAction SilentlyContinue
$sizeAfter = ($filesAfter | Measure-Object -Property Length -Sum).Sum
$freed = [math]::Round(($sizeBefore - $sizeAfter)/1MB, 1)
$totalFreed += $freed
OK ("Liberati $freed MB (eliminati: $deleted, in uso: $skipped)")
}
W ''
OK ("Spazio totale liberato: $totalFreed MB")
'@
# ----- RESET NET (ATTENZIONE: serve riavvio) -----
$diagBlocks['resetnet'] = @'
H1 "RESET STACK DI RETE"
W "ATTENZIONE: queste operazioni richiedono il RIAVVIO del computer." '#F7768E'
W "Vengono ripristinati Winsock, TCP/IP e cache DNS." '#7DCFFF'
H2 'Reset Winsock'
Status 'netsh winsock reset...'
Run-Native -Cmd 'netsh.exe' -Arguments @('winsock','reset') | Out-Null
if (Should-Stop) { return }
H2 'Reset stack TCP/IP'
Status 'netsh int ip reset...'
Run-Native -Cmd 'netsh.exe' -Arguments @('int','ip','reset') | Out-Null
if (Should-Stop) { return }
H2 'Reset cache ARP'
Status 'netsh interface ip delete arpcache...'
Run-Native -Cmd 'netsh.exe' -Arguments @('interface','ip','delete','arpcache') | Out-Null
if (Should-Stop) { return }
H2 'Rilascio e rinnovo IP'
Run-Native -Cmd 'ipconfig.exe' -Arguments @('/release') | Out-Null
Run-Native -Cmd 'ipconfig.exe' -Arguments @('/renew') | Out-Null
Run-Native -Cmd 'ipconfig.exe' -Arguments @('/flushdns') | Out-Null
W ''
W "==================================================================" '#E0AF68'
WARN 'RIAVVIA IL COMPUTER per completare il reset.'
W "==================================================================" '#E0AF68'
'@
# ----- DIAGNOSTICA COMPLETA -----
$diagBlocks['full'] = @'
H1 "DIAGNOSTICA COMPLETA - AVVIO"
W "Verranno eseguite tutte le verifiche non distruttive." '#7DCFFF'
W "Tempo stimato: 15-30 minuti." '#565F89'
$started = Get-Date
& ([scriptblock]::Create($Blocks['sysinfo']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['perf']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['disk']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['memory']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['gpu']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['drivers']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['events']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['netfull']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['sfc']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['dism']))
if (Should-Stop) { return }
& ([scriptblock]::Create($Blocks['chkdsk']))
$elapsed = (Get-Date) - $started
H1 "DIAGNOSTICA COMPLETA - TERMINATA"
OK ("Durata totale: {0}h {1}m {2}s" -f $elapsed.Hours, $elapsed.Minutes, $elapsed.Seconds)
'@
# -----------------------------------------------------------------------------
# Avvio task in runspace separato
# -----------------------------------------------------------------------------
function Start-DiagnosticTask {
param([string]$Key, [string]$Title, [string]$Subtitle)
if ($script:syncHash.Running) { return }
if (-not $diagBlocks.ContainsKey($Key)) {
Set-Header "Errore" "Diagnostica '$Key' non trovata."
return
}
# Pulisce il documento e prepara per nuovo output
$ctrl.OutputBox.Document.Blocks.Clear()
$p = New-Object Windows.Documents.Paragraph
$p.Margin = New-Object Windows.Thickness(0)
$ctrl.OutputBox.Document.Blocks.Add($p)
Set-Header $Title $Subtitle
Set-Running -Running $true -StatusText "Avvio: $Title..."
$script:syncHash.Stop = $false
$entryBody = "`n& ([scriptblock]::Create(`$Blocks[`$TaskKey]))`n"
$fullScript = $helpersBlock + $entryBody
$script:runspace = [runspacefactory]::CreateRunspace()
$script:runspace.ApartmentState = "STA"
$script:runspace.ThreadOptions = "ReuseThread"
$script:runspace.Open()
$script:runspace.SessionStateProxy.SetVariable("syncHash", $script:syncHash)
$script:runspace.SessionStateProxy.SetVariable("Blocks", $diagBlocks)
$script:runspace.SessionStateProxy.SetVariable("TaskKey", $Key)
$script:psInstance = [powershell]::Create()
$script:psInstance.Runspace = $script:runspace
[void]$script:psInstance.AddScript($fullScript)
$script:asyncResult = $script:psInstance.BeginInvoke()
}
# Timer per monitorare completamento task
$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromMilliseconds(400)
$timer.Add_Tick({
if ($script:asyncResult -and $script:asyncResult.IsCompleted) {
try { $script:psInstance.EndInvoke($script:asyncResult) | Out-Null } catch {}
try { $script:psInstance.Dispose() } catch {}
try { $script:runspace.Close() } catch {}
$script:asyncResult = $null
$script:psInstance = $null
$script:runspace = $null
if ($script:syncHash.Stop) {
Set-Running -Running $false -StatusText "Interrotto dall'utente."
} else {
Set-Running -Running $false -StatusText "Operazione completata."
}
}
})
$timer.Start()
# -----------------------------------------------------------------------------
# Eventi UI - barra titolo
# -----------------------------------------------------------------------------
$ctrl.TitleBar.Add_MouseLeftButtonDown({ $window.DragMove() })
$ctrl.BtnMinimize.Add_Click({ $window.WindowState = 'Minimized' })
$ctrl.BtnMaximize.Add_Click({
if ($window.WindowState -eq 'Maximized') { $window.WindowState = 'Normal' }
else { $window.WindowState = 'Maximized' }
})
$ctrl.BtnClose.Add_Click({
if ($script:syncHash.Running) {
$r = [System.Windows.MessageBox]::Show($window, "C'e' una diagnostica in corso. Vuoi chiudere comunque?", "Conferma", "YesNo", "Warning")
if ($r -ne 'Yes') { return }
$script:syncHash.Stop = $true
if ($script:psInstance) { try { [void]$script:psInstance.BeginStop($null, $null) } catch {} }
}
$window.Close()
})
# -----------------------------------------------------------------------------
# Eventi UI - sidebar buttons
# -----------------------------------------------------------------------------
# --- Tutti i pulsanti sidebar aprono l anteprima ---
$ctrl.BtnSysInfo.Add_Click({ Show-Preview 'sysinfo' })
$ctrl.BtnSFC.Add_Click({ Show-Preview 'sfc' })
$ctrl.BtnDISM.Add_Click({ Show-Preview 'dism' })
$ctrl.BtnCHKDSK.Add_Click({ Show-Preview 'chkdsk' })
$ctrl.BtnEvents.Add_Click({ Show-Preview 'events' })
$ctrl.BtnDrivers.Add_Click({ Show-Preview 'drivers' })
$ctrl.BtnPerf.Add_Click({ Show-Preview 'perf' })
$ctrl.BtnNetFull.Add_Click({ Show-Preview 'netfull' })
$ctrl.BtnNetConfig.Add_Click({ Show-Preview 'netconfig' })
$ctrl.BtnPing.Add_Click({ Show-Preview 'ping' })
$ctrl.BtnDNS.Add_Click({ Show-Preview 'dns' })
$ctrl.BtnMTU.Add_Click({ Show-Preview 'mtu' })
$ctrl.BtnTrace.Add_Click({ Show-Preview 'trace' })
$ctrl.BtnWiFi.Add_Click({ Show-Preview 'wifi' })
$ctrl.BtnPorts.Add_Click({ Show-Preview 'ports' })
$ctrl.BtnTTFB.Add_Click({ Show-Preview 'ttfb' })
$ctrl.BtnAntivirus.Add_Click({ Show-Preview 'antivirus' })
$ctrl.BtnDisk.Add_Click({ Show-Preview 'disk' })
$ctrl.BtnMemory.Add_Click({ Show-Preview 'memory' })
$ctrl.BtnGPU.Add_Click({ Show-Preview 'gpu' })
$ctrl.BtnBattery.Add_Click({ Show-Preview 'battery' })
$ctrl.BtnFlushDNS.Add_Click({ Show-Preview 'flushdns' })
$ctrl.BtnCleanTemp.Add_Click({ Show-Preview 'cleantemp' })
$ctrl.BtnResetNet.Add_Click({ Show-Preview 'resetnet' })
# --- Pulsante AVVIA: esegue la diagnostica selezionata ---
$ctrl.BtnRunAll.Add_Click({
if ($script:syncHash.Running) { return }
$key = if ($script:selectedDiag) { $script:selectedDiag } else { 'full' }
$info = $diagInfo[$key]
if (-not $info) { return }
if ($info.Confirm) {
$icon = if ($info.Risk -eq 'attenzione') { 'Warning' } else { 'Question' }
$r = [System.Windows.MessageBox]::Show($window, $info.ConfirmMessage, 'Conferma esecuzione', 'YesNo', $icon)
if ($r -ne 'Yes') { return }
}
Start-DiagnosticTask -Key $key -Title $info.Title -Subtitle $info.Subtitle
})
# -----------------------------------------------------------------------------
# Bottoni inferiori
# -----------------------------------------------------------------------------
$ctrl.BtnStop.Add_Click({
$script:syncHash.Stop = $true
$ctrl.LblStatus.Text = "Interruzione in corso..."
$ctrl.BtnStop.IsEnabled = $false
if ($script:psInstance) {
try { [void]$script:psInstance.BeginStop($null, $null) } catch {}
}
})
$ctrl.BtnClear.Add_Click({
$ctrl.OutputBox.Document.Blocks.Clear()
$p = New-Object Windows.Documents.Paragraph
$p.Margin = New-Object Windows.Thickness(0)
$r = New-Object Windows.Documents.Run "Console pulita."
$r.Foreground = (New-Object Windows.Media.BrushConverter).ConvertFrom('#565F89')
$p.Inlines.Add($r)
$ctrl.OutputBox.Document.Blocks.Add($p)
})
$ctrl.BtnSave.Add_Click({
$dlg = New-Object Microsoft.Win32.SaveFileDialog
$dlg.Filter = "File di testo (*.txt)|*.txt|Tutti i file (*.*)|*.*"
$dlg.FileName = "diagnostica-windows-" + (Get-Date -Format 'yyyyMMdd-HHmmss') + ".txt"
if ($dlg.ShowDialog()) {
try {
$tr = New-Object Windows.Documents.TextRange($ctrl.OutputBox.Document.ContentStart, $ctrl.OutputBox.Document.ContentEnd)
$tr.Text | Out-File -FilePath $dlg.FileName -Encoding utf8
[System.Windows.MessageBox]::Show($window, "Log salvato:`n$($dlg.FileName)", "Salvato", "OK", "Information") | Out-Null
} catch {
[System.Windows.MessageBox]::Show($window, "Errore nel salvataggio:`n$($_.Exception.Message)", "Errore", "OK", "Error") | Out-Null
}
}
})
# Chiusura: pulisci runspace
$window.Add_Closed({
$script:syncHash.Stop = $true
if ($script:psInstance) {
try { [void]$script:psInstance.BeginStop($null, $null) } catch {}
try { $script:psInstance.Dispose() } catch {}
}
if ($script:runspace) {
try { $script:runspace.Close() } catch {}
}
$timer.Stop()
})
# -----------------------------------------------------------------------------
# Stato iniziale: mostra anteprima della diagnostica completa
# -----------------------------------------------------------------------------
Show-Preview 'full'
# -----------------------------------------------------------------------------
# Avvio
# -----------------------------------------------------------------------------
[void]$window.ShowDialog()