#Requires -RunAsAdministrator $LogFile = "$env:TEMP\RepairPC_$(Get-Date -Format 'yyyyMMdd_HHmmss').log" $ErrorActionPreference = "SilentlyContinue" function Write-Log { param([string]$Message, [string]$Level = "INFO") $timestamp = Get-Date -Format "HH:mm:ss" Add-Content -Path $LogFile -Value "[$timestamp][$Level] $Message" switch ($Level) { "OK" { Write-Host " [OK] $Message" -ForegroundColor Green } "WARN" { Write-Host " [!] $Message" -ForegroundColor Yellow } "ERROR" { Write-Host " [X] $Message" -ForegroundColor Red } "FIX" { Write-Host " [->] $Message" -ForegroundColor Cyan } "HEAD" { Write-Host "`n == $Message ==" -ForegroundColor Magenta } default { Write-Host " [i] $Message" -ForegroundColor Gray } } } # Lance une commande en arriere-plan avec spinner + chrono function Invoke-WithSpinner { param( [string]$Label, [scriptblock]$ScriptBlock ) $frames = @('|', '/', '-', '\') $i = 0 $start = Get-Date $cursorX = $Host.UI.RawUI.CursorPosition.X $cursorY = $Host.UI.RawUI.CursorPosition.Y # Lancement en job background $job = Start-Job -ScriptBlock $ScriptBlock Write-Host "" # ligne vide pour le spinner while ($job.State -eq 'Running') { $elapsed = [math]::Round(((Get-Date) - $start).TotalSeconds, 0) $frame = $frames[$i % $frames.Length] # Revenir au debut de la ligne du spinner $pos = $Host.UI.RawUI.CursorPosition $pos.Y = $cursorY + 1 $pos.X = 0 $Host.UI.RawUI.CursorPosition = $pos Write-Host (" [{0}] {1}... {2}s" -f $frame, $Label, $elapsed) -NoNewline -ForegroundColor DarkCyan Start-Sleep -Milliseconds 200 $i++ } # Effacer la ligne du spinner $pos = $Host.UI.RawUI.CursorPosition $pos.Y = $cursorY + 1 $pos.X = 0 $Host.UI.RawUI.CursorPosition = $pos Write-Host (" " * 70) -NoNewline $pos.X = 0 $Host.UI.RawUI.CursorPosition = $pos $elapsed = [math]::Round(((Get-Date) - $start).TotalSeconds, 0) $output = Receive-Job $job Remove-Job $job Write-Host (" [OK] {0} termine en {1}s" -f $Label, $elapsed) -ForegroundColor Green Add-Content -Path $LogFile -Value "[INFO] $Label termine en ${elapsed}s" return $output } function Show-Banner { Clear-Host Write-Host "=============================================" -ForegroundColor DarkMagenta Write-Host " RepairPC - Diagnostic et Reparation " -ForegroundColor DarkMagenta Write-Host " Windows Auto-Fix Script " -ForegroundColor DarkMagenta Write-Host "=============================================" -ForegroundColor DarkMagenta Write-Host " Journal : $LogFile`n" -ForegroundColor DarkGray } function Show-Result { param([int]$Fixed, [int]$Errors) Write-Host "`n=============================================" -ForegroundColor DarkMagenta Write-Host " RESUME FINAL " -ForegroundColor DarkMagenta Write-Host "=============================================" -ForegroundColor DarkMagenta Write-Host " Reparations effectuees : $Fixed" -ForegroundColor Green if ($Errors -gt 0) { Write-Host " Problemes persistants : $Errors" -ForegroundColor Red } else { Write-Host " Problemes persistants : $Errors" -ForegroundColor Green } Write-Host " Journal complet : $LogFile`n" -ForegroundColor DarkGray } $global:Fixed = 0 $global:Errors = 0 function Get-SystemInfo { Write-Log "Informations systeme" "HEAD" $os = Get-CimInstance Win32_OperatingSystem $cpu = Get-CimInstance Win32_Processor | Select-Object -First 1 $ram = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2) $freeRam = [math]::Round($os.FreePhysicalMemory / 1MB, 2) $updays = ((Get-Date) - $os.LastBootUpTime).Days Write-Log "OS : $($os.Caption) ($($os.OSArchitecture))" Write-Log "CPU : $($cpu.Name)" Write-Log "RAM : $freeRam Go libres / $ram Go total" Write-Log "Uptime : $updays jour(s)" Write-Log "Hote : $env:COMPUTERNAME | Utilisateur : $env:USERNAME" } function Repair-SystemFiles { Write-Log "Verification des fichiers systeme (SFC + DISM)" "HEAD" # SFC avec spinner Write-Log "SFC : analyse en cours..." "FIX" $sfcOutput = Invoke-WithSpinner -Label "sfc /scannow" -ScriptBlock { & sfc /scannow 2>&1 | Out-String } if ($sfcOutput -match "aucune violation" -or $sfcOutput -match "no integrity violations") { Write-Log "SFC : aucun fichier corrompu" "OK" } elseif ($sfcOutput -match "a repare" -or $sfcOutput -match "successfully repaired") { Write-Log "SFC : des fichiers ont ete repares" "OK" $global:Fixed++ } else { Write-Log "SFC : fichiers corrompus non repares, lancement de DISM..." "WARN" # DISM avec spinner Write-Log "DISM : restauration de l'image en cours (peut durer 10-20 min)..." "FIX" $dismOutput = Invoke-WithSpinner -Label "DISM /RestoreHealth" -ScriptBlock { & DISM /Online /Cleanup-Image /RestoreHealth 2>&1 | Out-String } if ($dismOutput -match "operation a reussi" -or $dismOutput -match "The operation completed successfully") { Write-Log "DISM : image reparee avec succes" "OK" $global:Fixed++ } else { Write-Log "DISM : echec de la reparation" "ERROR" $global:Errors++ } } } function Repair-Disk { Write-Log "Verification des disques" "HEAD" $drives = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Root -match "^[A-Z]:\\" } foreach ($drive in $drives) { $letter = $drive.Root.TrimEnd('\') $freeGB = [math]::Round($drive.Free / 1GB, 2) $usedGB = [math]::Round($drive.Used / 1GB, 2) $totalGB = $freeGB + $usedGB Write-Log "Lecteur $letter - Libre : $freeGB Go / $totalGB Go" if ($totalGB -gt 0) { $pct = [math]::Round(($freeGB / $totalGB) * 100, 1) } else { $pct = 100 } if ($pct -lt 10) { Write-Log "Espace disque CRITIQUE sur $letter ($pct pourcent libre)" "ERROR" $global:Errors++ } elseif ($pct -lt 20) { Write-Log "Espace disque faible sur $letter ($pct pourcent libre)" "WARN" } else { Write-Log "Espace disque OK sur $letter ($pct pourcent libre)" "OK" } Write-Log "CHKDSK sur $letter..." "FIX" $chk = Invoke-WithSpinner -Label "chkdsk $letter" -ScriptBlock { param($l) & chkdsk $l /scan 2>&1 | Out-String } if ($chk -match "Aucun probleme" -or $chk -match "No further action" -or $chk -match "0 bad sectors") { Write-Log "CHKDSK $letter : aucun probleme" "OK" } else { Write-Log "CHKDSK $letter : problemes detectes (planifier /f au prochain demarrage)" "WARN" } } Write-Log "Lecture S.M.A.R.T. des disques physiques" "FIX" $physDisks = Get-PhysicalDisk foreach ($d in $physDisks) { $health = $d.HealthStatus if ($health -eq "Healthy") { Write-Log "Disque '$($d.FriendlyName)' - Sante : $health" "OK" } else { Write-Log "Disque '$($d.FriendlyName)' - Sante : $health" "ERROR" $global:Errors++ } } } function Check-Memory { Write-Log "Memoire vive" "HEAD" $os = Get-CimInstance Win32_OperatingSystem $totalMB = [math]::Round($os.TotalVisibleMemorySize / 1024, 0) $freeMB = [math]::Round($os.FreePhysicalMemory / 1024, 0) $usePct = [math]::Round((($totalMB - $freeMB) / $totalMB) * 100, 1) Write-Log "RAM utilisee : $($totalMB - $freeMB) Mo / $totalMB Mo ($usePct pourcent)" if ($usePct -gt 90) { Write-Log "Utilisation RAM critique ($usePct pourcent)" "ERROR" $global:Errors++ [System.GC]::Collect() } elseif ($usePct -gt 75) { Write-Log "Utilisation RAM elevee ($usePct pourcent)" "WARN" } else { Write-Log "RAM OK ($usePct pourcent utilise)" "OK" } } function Repair-Network { Write-Log "Diagnostic reseau" "HEAD" $gw = (Get-NetRoute -DestinationPrefix "0.0.0.0/0" -ErrorAction SilentlyContinue | Sort-Object RouteMetric | Select-Object -First 1).NextHop if ($gw) { $pingGW = Test-Connection -ComputerName $gw -Count 2 -Quiet if ($pingGW) { Write-Log "Passerelle $gw joignable" "OK" } else { Write-Log "Passerelle $gw non joignable" "ERROR"; $global:Errors++ } } else { Write-Log "Aucune passerelle par defaut trouvee" "WARN" } $pingNet = Test-Connection -ComputerName "8.8.8.8" -Count 2 -Quiet if ($pingNet) { Write-Log "Connectivite Internet (8.8.8.8) : OK" "OK" } else { Write-Log "Pas d'acces Internet - Reparation Winsock + IP stack..." "WARN" & netsh winsock reset | Out-Null & netsh int ip reset | Out-Null & ipconfig /flushdns | Out-Null Write-Log "Reparation reseau effectuee - redemarrage recommande" "FIX" $global:Fixed++ } $dns = Resolve-DnsName "www.google.com" -ErrorAction SilentlyContinue if ($dns) { Write-Log "Resolution DNS : OK" "OK" } else { Write-Log "Resolution DNS : ECHEC" "ERROR"; $global:Errors++ } } function Repair-Services { Write-Log "Verification des services critiques" "HEAD" $criticals = @( @{ Name = "wuauserv"; Display = "Windows Update" }, @{ Name = "Winmgmt"; Display = "WMI" }, @{ Name = "EventLog"; Display = "Journal des evenements" }, @{ Name = "Schedule"; Display = "Planificateur de taches" }, @{ Name = "BITS"; Display = "BITS" }, @{ Name = "CryptSvc"; Display = "Services de chiffrement" }, @{ Name = "Spooler"; Display = "Spooler d'impression" }, @{ Name = "W32Time"; Display = "Heure Windows" } ) foreach ($svc in $criticals) { $s = Get-Service -Name $svc.Name -ErrorAction SilentlyContinue if (-not $s) { Write-Log "$($svc.Display) : introuvable" "WARN"; continue } if ($s.Status -ne "Running") { Write-Log "$($svc.Display) arrete - redemarrage..." "FIX" try { Start-Service -Name $svc.Name -ErrorAction Stop Write-Log "$($svc.Display) : demarre" "OK" $global:Fixed++ } catch { Write-Log "$($svc.Display) : impossible de demarrer" "ERROR" $global:Errors++ } } else { Write-Log "$($svc.Display) : OK" "OK" } } } function Check-WindowsUpdate { Write-Log "Verification Windows Update" "HEAD" $wu = Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 1 if ($wu) { $days = ((Get-Date) - $wu.InstalledOn).Days Write-Log "Derniere mise a jour : il y a $days jour(s) ($($wu.HotFixID))" if ($days -gt 60) { Write-Log "Systeme non mis a jour depuis plus de 60 jours !" "WARN"; $global:Errors++ } else { Write-Log "Mises a jour recentes OK" "OK" } } else { Write-Log "Impossible de lire l'historique des mises a jour" "WARN" } } function Clean-TempFiles { Write-Log "Nettoyage des fichiers temporaires" "HEAD" $folders = @($env:TEMP, $env:TMP, "C:\Windows\Temp", "C:\Windows\Prefetch") $totalFreed = 0 foreach ($folder in $folders) { if (Test-Path $folder) { $size = (Get-ChildItem $folder -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum $sizeMB = [math]::Round($size / 1MB, 2) Get-ChildItem $folder -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue Write-Log "Nettoye : $folder ($sizeMB Mo liberes)" "OK" $totalFreed += $sizeMB $global:Fixed++ } } Clear-RecycleBin -Force -ErrorAction SilentlyContinue Write-Log "Corbeille videe" "OK" Write-Log "Total libere : $([math]::Round($totalFreed,2)) Mo" "OK" } function Check-EventLog { Write-Log "Analyse du journal des evenements (24 dernieres heures)" "HEAD" $since = (Get-Date).AddHours(-24) $errors = Get-WinEvent -FilterHashtable @{ LogName='System'; Level=2; StartTime=$since } -MaxEvents 50 -ErrorAction SilentlyContinue $criticals = Get-WinEvent -FilterHashtable @{ LogName='System'; Level=1; StartTime=$since } -MaxEvents 20 -ErrorAction SilentlyContinue $errCount = ($errors | Measure-Object).Count $critCount = ($criticals | Measure-Object).Count Write-Log "Erreurs systeme (24h) : $errCount" Write-Log "Critiques systeme (24h) : $critCount" if ($critCount -gt 0) { Write-Log "Evenements critiques detectes !" "ERROR"; $global:Errors++ } elseif ($errCount -gt 10) { Write-Log "Nombre d'erreurs eleve ($errCount)" "WARN" } else { Write-Log "Journal systeme : OK" "OK" } } # --- MAIN --- Show-Banner $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Host " [X] Ce script doit etre execute en tant qu'Administrateur !" -ForegroundColor Red exit 1 } Write-Log "Demarrage du diagnostic - $(Get-Date -Format 'dd/MM/yyyy HH:mm:ss')" Get-SystemInfo Repair-SystemFiles Repair-Disk Check-Memory Repair-Network Repair-Services Check-WindowsUpdate Clean-TempFiles Check-EventLog Show-Result -Fixed $global:Fixed -Errors $global:Errors if ($global:Errors -gt 0) { Write-Host " Certains problemes necessitent un redemarrage ou une intervention manuelle." -ForegroundColor Yellow } else { Write-Host " Votre systeme est en bonne sante !" -ForegroundColor Green } Write-Host "`n Appuyez sur une touche pour quitter..." -ForegroundColor DarkGray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")