# MehdiCore - genere par build.ps1 - NE PAS EDITER # Build 2026-06-26T13:37:38.368701 $script:AppsCatalogJson = @' [ { "name": "Chris Titus WinUtil", "category": "Maintenance", "command": "irm christitus.com/win | iex", "description": "Boite a outils Windows : debloat, tweaks, installation d'apps" }, { "name": "7-Zip", "category": "Utilitaires (ephemere)", "portable": { "file": "7-ZipPortable.zip", "exe": "7-ZipPortable.exe", "ephemeral": true }, "description": "Archiveur de fichiers - lance puis efface (aucune trace)" }, { "name": "Notepad++", "category": "Utilitaires (ephemere)", "portable": { "file": "Notepad++Portable.zip", "exe": "Notepad++Portable.exe", "ephemeral": true }, "description": "Editeur de texte avance - lance puis efface (aucune trace)" }, { "name": "Process Explorer", "category": "Diagnostic (ephemere)", "portable": { "file": "ProcessExplorerPortable.zip", "exe": "ProcessExplorerPortable.exe", "ephemeral": true }, "description": "Gestionnaire de processus avance (Sysinternals) - aucune trace" }, { "name": "Autoruns", "category": "Diagnostic (ephemere)", "portable": { "file": "AutorunsPortable.zip", "exe": "AutorunsPortable.exe", "ephemeral": true }, "description": "Programmes au demarrage (Sysinternals) - aucune trace" }, { "name": "UniGetUI", "category": "Maintenance (cache)", "portable": { "file": "UniGetUI.zip", "exe": "UniGetUI.exe" }, "description": "Gestionnaire d'apps (213 Mo) - telecharge une fois puis instantane" }, { "name": "SUPERAntiSpyware", "category": "Securite (cache)", "portable": { "file": "SuperAntiSpyWare.zip", "exe": "SUPERAntiSpyware Professional X.exe" }, "description": "Anti-malware (763 Mo) - telecharge une fois puis instantane" } ] '@ # ---- core/bootstrap.ps1 ---- # ============================================================ # MehdiCore - core/bootstrap.ps1 # Configuration globale + verification des prerequis # ============================================================ # Force la console en UTF-8 (affichage correct des blocs et accents) try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 chcp 65001 > $null 2>&1 } catch { } $script:MehdiCore = @{ Name = 'MehdiCore' Version = '0.3.0' Url = 'https://mehdicore.i02.be/mehdicore.ps1' ToolsBaseUrl = 'https://mehdicore.i02.be/app' StreamHost = 'dav.mehdicore.i02.be' StreamHttp = 'https://dav.mehdicore.i02.be' StreamUnc = '\\dav.mehdicore.i02.be@SSL\DavWWWRoot' LogPath = (Join-Path $env:TEMP 'MehdiCore.log') } # Dossier des outils portables : a cote du script si lance en fichier # (ideal cle USB), sinon dans le profil utilisateur. if ($PSCommandPath) { $script:MehdiCore.ToolsDir = Join-Path (Split-Path -Parent $PSCommandPath) 'Tools' } else { $script:MehdiCore.ToolsDir = Join-Path $env:USERPROFILE 'MehdiCore\Tools' } # Verifie si la session courante est elevee (administrateur) function Test-Admin { $id = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($id) return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } # Verifie la version de PowerShell minimale function Test-Prerequisites { if ($PSVersionTable.PSVersion.Major -lt 5) { Write-Warning "PowerShell 5.1 minimum est requis (version detectee : $($PSVersionTable.PSVersion))." return $false } return $true } # Relance MehdiCore en tant qu'administrateur si necessaire. # - Lance comme fichier local -> relance le meme fichier (-File), fenetre maintenue. # - Lance via "irm | iex" -> relance depuis l'URL. # Retourne $true si la session est deja elevee, $false sinon (et relance). function Assert-Admin { if (Test-Admin) { return $true } Write-Warning 'MehdiCore requiert les droits administrateur. Tentative d''elevation...' try { if ($PSCommandPath) { $argLine = "-NoProfile -NoExit -ExecutionPolicy Bypass -File `"$PSCommandPath`"" } else { $argLine = "-NoProfile -ExecutionPolicy Bypass -Command `"irm $($script:MehdiCore.Url) | iex`"" } Start-Process -FilePath 'powershell.exe' -Verb RunAs -ArgumentList $argLine | Out-Null } catch { Write-Warning "Elevation refusee ou impossible : $($_.Exception.Message)" Start-Sleep -Seconds 4 } return $false } # ---- core/ui.ps1 ---- # ============================================================ # MehdiCore - core/ui.ps1 # Affichage : banniere, moteur de menu, helpers visuels # ============================================================ function Show-Banner { Clear-Host Write-Host "███╗ ███╗███████╗██╗ ██╗██████╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗" -ForegroundColor Cyan Write-Host "████╗ ████║██╔════╝██║ ██║██╔══██╗██║ ██╔════╝██╔═══██╗██╔══██╗██╔════╝" -ForegroundColor Cyan Write-Host "██╔████╔██║█████╗ ███████║██║ ██║██║ ██║ ██║ ██║██████╔╝█████╗ " -ForegroundColor Cyan Write-Host "██║╚██╔╝██║██╔══╝ ██╔══██║██║ ██║██║ ██║ ██║ ██║██╔══██╗██╔══╝ " -ForegroundColor Cyan Write-Host "██║ ╚═╝ ██║███████╗██║ ██║██████╔╝██║ ╚██████╗╚██████╔╝██║ ██║███████╗" -ForegroundColor Cyan Write-Host "╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝" -ForegroundColor Cyan Write-Host "" Write-Host " Boite a outils Windows - v$($script:MehdiCore.Version)" -ForegroundColor DarkGray Write-Host "" } $script:MehdiCrumbs = @() # En-tete compact (sous-menus + ecrans d'action) : titre court + fil d'Ariane. function Show-Header { Clear-Host Write-Host '' Write-Host ' MEHDICORE' -ForegroundColor Cyan -NoNewline Write-Host " v$($script:MehdiCore.Version)" -ForegroundColor DarkGray if ($script:MehdiCrumbs.Count -gt 0) { Write-Host (' ' + ($script:MehdiCrumbs -join ' > ')) -ForegroundColor DarkCyan } Write-Host (' ' + ('-' * 62)) -ForegroundColor DarkGray Write-Host '' } # Moteur de menu generique. # -Items : @{ Label; Desc; Action } ou @{ Section = 'Titre' } (non selectionnable) # -BackLabel : libelle de la sortie (0). 000 = quitter MehdiCore. function Invoke-Menu { param( [Parameter(Mandatory = $true)][string]$Title, [Parameter(Mandatory = $true)][array]$Items, [string]$BackLabel = 'Retour' ) $script:MehdiCrumbs += $Title try { while ($true) { if ($script:MehdiQuit) { return } if ($script:MehdiCrumbs.Count -le 1) { Show-Banner } else { Show-Header } $selectable = @() $n = 0 foreach ($it in $Items) { if ($it.Section) { Write-Host '' Write-Host (' ' + $it.Section.ToUpper()) -ForegroundColor Yellow Write-Host (' ' + ('.' * $it.Section.Length)) -ForegroundColor DarkGray continue } $n++ $selectable += $it Write-Host (" {0,2}. " -f $n) -ForegroundColor Cyan -NoNewline Write-Host $it.Label -ForegroundColor White if ($it.Desc) { Write-Host (' ' + $it.Desc) -ForegroundColor DarkGray } } Write-Host '' Write-Host (' 0. ' + $BackLabel) -ForegroundColor DarkGray Write-Host ' 000. Quitter MehdiCore' -ForegroundColor DarkGray Write-Host '' $choice = Read-Host ' Choix' if ($choice -eq '000') { $script:MehdiQuit = $true; return } if ($choice -eq '0') { return } if ([string]::IsNullOrWhiteSpace($choice)) { continue } $idx = 0 if ([int]::TryParse($choice, [ref]$idx) -and $idx -ge 1 -and $idx -le $selectable.Count) { $action = $selectable[$idx - 1].Action if ($action) { & $action } } else { Write-Host ' Choix invalide.' -ForegroundColor Red Start-Sleep -Milliseconds 800 } } } finally { if ($script:MehdiCrumbs.Count -le 1) { $script:MehdiCrumbs = @() } else { $script:MehdiCrumbs = @($script:MehdiCrumbs[0..($script:MehdiCrumbs.Count - 2)]) } } } # ---- core/utils.ps1 ---- # ============================================================ # MehdiCore - core/utils.ps1 # Utilitaires : log, confirmation, pause, execution securisee # ============================================================ function Write-Log { param( [Parameter(Mandatory = $true)][string]$Message, [ValidateSet('INFO', 'WARN', 'ERROR')][string]$Level = 'INFO' ) $line = "{0} [{1}] {2}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $Message try { Add-Content -Path $script:MehdiCore.LogPath -Value $line -ErrorAction SilentlyContinue } catch { } } function Pause-Continue { Write-Host "" Write-Host " Appuie sur une touche pour continuer..." -ForegroundColor DarkGray try { [void][System.Console]::ReadKey($true) } catch { Read-Host | Out-Null } } function Confirm-Action { param([string]$Message = 'Confirmer ?') $answer = Read-Host " $Message [o/N]" return ($answer -match '^(o|oui|y|yes)$') } # Execute une action de maniere securisee : titre, confirmation optionnelle, # capture des erreurs, journalisation, pause finale. function Invoke-Step { param( [Parameter(Mandatory = $true)][string]$Title, [Parameter(Mandatory = $true)][scriptblock]$Action, [switch]$Confirm, [switch]$NoPause ) Show-Header Write-Host " >> $Title" -ForegroundColor Yellow Write-Host "" if ($Confirm -and -not (Confirm-Action "Lancer cette operation ?")) { Write-Host " Operation annulee." -ForegroundColor DarkGray if (-not $NoPause) { Pause-Continue } return } Write-Log "Debut : $Title" try { & $Action Write-Host "" Write-Host " [OK] Operation terminee." -ForegroundColor Green Write-Log "Succes : $Title" } catch { Write-Host "" Write-Host " [ERREUR] $($_.Exception.Message)" -ForegroundColor Red Write-Log "Erreur : $Title -> $($_.Exception.Message)" 'ERROR' } if (-not $NoPause) { Pause-Continue } } # Ecrit une valeur de registre en creant la cle si besoin. function Set-MehdiReg { param( [Parameter(Mandatory = $true)][string]$Path, [Parameter(Mandatory = $true)][string]$Name, [Parameter(Mandatory = $true)]$Value, [ValidateSet('DWord', 'String', 'ExpandString', 'QWord', 'Binary')][string]$Type = 'DWord' ) if (-not (Test-Path $Path)) { New-Item -Path $Path -Force | Out-Null } New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType $Type -Force | Out-Null } # Redemarre l'explorateur Windows (pour appliquer certains tweaks). function Restart-MehdiExplorer { Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 1 if (-not (Get-Process -Name explorer -ErrorAction SilentlyContinue)) { Start-Process explorer.exe } } # ---- modules/repair.ps1 ---- # ============================================================ # MehdiCore - modules/repair.ps1 # Module 1 : Reparation systeme (complet, avec descriptions) # ============================================================ # ---- Helpers internes ---- function Invoke-MehdiIntegrityScan { Write-Host ' [1/2] DISM /Online /Cleanup-Image /RestoreHealth' -ForegroundColor Cyan DISM.exe /Online /Cleanup-Image /RestoreHealth Write-Host '' Write-Host ' [2/2] SFC /scannow' -ForegroundColor Cyan sfc.exe /scannow } function Reset-MehdiNetwork { ipconfig /flushdns netsh winsock reset netsh int ip reset netsh winhttp reset proxy Write-Host '' Write-Host ' Reseau reinitialise. Un redemarrage est recommande.' -ForegroundColor Yellow } function Reset-MehdiWindowsUpdate { $services = @('wuauserv', 'usosvc', 'dosvc', 'bits', 'cryptsvc', 'msiserver') foreach ($s in $services) { Stop-Service -Name $s -Force -ErrorAction SilentlyContinue } $folders = @((Join-Path $env:windir 'SoftwareDistribution'), (Join-Path $env:windir 'System32\catroot2')) foreach ($f in $folders) { if (Test-Path $f) { $old = "$f.old" if (Test-Path $old) { Remove-Item $old -Recurse -Force -ErrorAction SilentlyContinue } Rename-Item -Path $f -NewName ("{0}.old" -f (Split-Path $f -Leaf)) -Force -ErrorAction SilentlyContinue Write-Host " Renomme : $f -> $f.old" } } foreach ($s in $services) { Start-Service -Name $s -ErrorAction SilentlyContinue } Write-Host '' Write-Host ' Composants Windows Update reinitialises.' -ForegroundColor Green } function Clear-MehdiTemp { $targets = @($env:TEMP, (Join-Path $env:windir 'Temp'), (Join-Path $env:windir 'Prefetch')) foreach ($t in $targets) { if (Test-Path $t) { Get-ChildItem -Path $t -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue Write-Host " Nettoye : $t" } } } function Reset-MehdiPrintSpooler { Stop-Service -Name Spooler -Force -ErrorAction SilentlyContinue $queue = Join-Path $env:windir 'System32\spool\PRINTERS' if (Test-Path $queue) { Get-ChildItem -Path $queue -Force -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue } Start-Service -Name Spooler -ErrorAction SilentlyContinue Write-Host ' Spouleur d''impression reinitialise.' -ForegroundColor Green } function Register-MehdiUwpApps { Get-AppxPackage -AllUsers | Where-Object { $_.InstallLocation } | ForEach-Object { Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml" -ErrorAction SilentlyContinue } Write-Host ' Applications UWP reenregistrees.' -ForegroundColor Green } function Test-MehdiPendingReboot { $keys = @( 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending', 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' ) foreach ($k in $keys) { if (Test-Path $k) { return $true } } $pfro = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name PendingFileRenameOperations -ErrorAction SilentlyContinue if ($pfro -and $pfro.PendingFileRenameOperations) { return $true } return $false } # ---- Sous-menus ---- function Show-RepairIntegrityMenu { $items = @( @{ Label = 'Reparation complete (DISM + SFC)'; Desc = 'Repare l''image Windows puis les fichiers systeme - la sequence a lancer en premier.'; Action = { Invoke-Step 'Reparation integrite complete' { Invoke-MehdiIntegrityScan } } } @{ Label = 'SFC /scannow'; Desc = 'Verifie et repare les fichiers systeme corrompus de Windows.'; Action = { Invoke-Step 'SFC /scannow' { sfc.exe /scannow } } } @{ Label = 'SFC /verifyonly'; Desc = 'Verifie les fichiers systeme sans rien reparer (diagnostic).'; Action = { Invoke-Step 'SFC /verifyonly' { sfc.exe /verifyonly } } } @{ Label = 'DISM /CheckHealth'; Desc = 'Verification rapide : signale si l''image Windows est marquee comme corrompue.'; Action = { Invoke-Step 'DISM /CheckHealth' { DISM.exe /Online /Cleanup-Image /CheckHealth } } } @{ Label = 'DISM /ScanHealth'; Desc = 'Analyse approfondie de l''image Windows a la recherche de corruption.'; Action = { Invoke-Step 'DISM /ScanHealth' { DISM.exe /Online /Cleanup-Image /ScanHealth } } } @{ Label = 'DISM /RestoreHealth'; Desc = 'Repare l''image Windows en telechargeant les fichiers sains via Windows Update.'; Action = { Invoke-Step 'DISM /RestoreHealth' { DISM.exe /Online /Cleanup-Image /RestoreHealth } } } @{ Label = 'DISM /AnalyzeComponentStore'; Desc = 'Indique si le dossier WinSxS a besoin d''etre nettoye.'; Action = { Invoke-Step 'DISM /AnalyzeComponentStore' { DISM.exe /Online /Cleanup-Image /AnalyzeComponentStore } } } @{ Label = 'Nettoyer WinSxS (StartComponentCleanup)'; Desc = 'Libere de l''espace en supprimant les anciennes versions de composants Windows.'; Action = { Invoke-Step 'DISM /StartComponentCleanup' { DISM.exe /Online /Cleanup-Image /StartComponentCleanup } -Confirm } } @{ Label = 'Annuler les actions DISM en attente'; Desc = 'Debloque une mise a jour figee en annulant les operations en attente.'; Action = { Invoke-Step 'DISM /RevertPendingActions' { DISM.exe /Online /Cleanup-Image /RevertPendingActions } -Confirm } } ) Invoke-Menu -Title 'INTEGRITE SYSTEME' -Items $items } function Show-RepairDiskMenu { $items = @( @{ Label = 'CHKDSK C: /scan'; Desc = 'Analyse le disque systeme en ligne, sans le verrouiller (lecture seule).'; Action = { Invoke-Step 'CHKDSK C: /scan' { chkdsk.exe C: /scan } } } @{ Label = 'Repair-Volume -Scan'; Desc = 'Equivalent PowerShell d''une analyse de volume sans reparation.'; Action = { Invoke-Step 'Repair-Volume -Scan' { Repair-Volume -DriveLetter C -Scan } } } @{ Label = 'Planifier une analyse au redemarrage'; Desc = 'Marque le disque pour une verification complete (chkdsk) au prochain demarrage.'; Action = { Invoke-Step 'Planifier chkdsk au redemarrage' { fsutil dirty set C: ; Write-Host ' Analyse complete planifiee au prochain redemarrage.' -ForegroundColor Yellow } -Confirm } } @{ Label = 'Optimiser le disque C:'; Desc = 'Defragmente un disque dur ou envoie un TRIM a un SSD pour garder les performances.'; Action = { Invoke-Step 'Optimize-Volume C' { Optimize-Volume -DriveLetter C -Verbose } -Confirm } } @{ Label = 'Etat de sante des disques (SMART)'; Desc = 'Affiche l''etat materiel des disques pour anticiper une panne.'; Action = { Invoke-Step 'Etat des disques' { Get-PhysicalDisk | Select-Object FriendlyName, MediaType, @{ n = 'Taille(GB)'; e = { [math]::Round($_.Size / 1GB) } }, HealthStatus, OperationalStatus | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Lister les volumes'; Desc = 'Liste les volumes, leur lettre, systeme de fichiers et espace libre.'; Action = { Invoke-Step 'Volumes' { Get-Volume | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Lister les disques et partitions'; Desc = 'Vue d''ensemble des disques physiques et de leurs partitions.'; Action = { Invoke-Step 'Disques et partitions' { Get-Disk | Format-Table Number, FriendlyName, @{n='Taille(GB)';e={[math]::Round($_.Size/1GB)}}, PartitionStyle -AutoSize | Out-Host; Get-Partition | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Espace disque par lecteur'; Desc = 'Espace libre et utilise par lettre de lecteur, en un coup d''oeil.'; Action = { Invoke-Step 'Espace disque' { Get-PSDrive -PSProvider FileSystem | Select-Object Name, @{ n = 'Libre(GB)'; e = { [math]::Round($_.Free / 1GB, 1) } }, @{ n = 'Utilise(GB)'; e = { [math]::Round($_.Used / 1GB, 1) } } | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Ouvrir diskpart'; Desc = 'Outil avance de gestion des partitions (pour utilisateurs experimentes).'; Action = { Invoke-Step 'diskpart' { Start-Process 'diskpart.exe' } } } ) Invoke-Menu -Title 'DISQUE' -Items $items } function Show-RepairNetworkMenu { $items = @( @{ Label = 'Vider le cache DNS'; Desc = 'Resout les erreurs de sites inaccessibles dues a un cache DNS perime.'; Action = { Invoke-Step 'ipconfig /flushdns' { ipconfig /flushdns } } } @{ Label = 'Afficher le cache DNS'; Desc = 'Montre les noms de domaines actuellement en cache (diagnostic).'; Action = { Invoke-Step 'ipconfig /displaydns' { ipconfig /displaydns | Out-Host } } } @{ Label = 'Renouveler l adresse IP'; Desc = 'Libere puis redemande une adresse IP au routeur (DHCP).'; Action = { Invoke-Step 'Renouvellement IP' { ipconfig /release; ipconfig /renew } } } @{ Label = 'Reenregistrer le DNS'; Desc = 'Force la reinscription du PC aupres du serveur DNS.'; Action = { Invoke-Step 'ipconfig /registerdns' { ipconfig /registerdns } } } @{ Label = 'Test de connexion (ping 8.8.8.8)'; Desc = 'Verifie si Internet repond, via le DNS Google.'; Action = { Invoke-Step 'Ping 8.8.8.8' { ping 8.8.8.8 } } } @{ Label = 'Tracer la route (tracert 8.8.8.8)'; Desc = 'Affiche le chemin reseau jusqu a une destination, pour localiser une coupure.'; Action = { Invoke-Step 'tracert' { tracert 8.8.8.8 | Out-Host } } } @{ Label = 'Connexions actives (netstat -ano)'; Desc = 'Liste les connexions reseau ouvertes et le processus associe.'; Action = { Invoke-Step 'netstat -ano' { netstat -ano | Out-Host } } } @{ Label = 'Table de routage (route print)'; Desc = 'Affiche les routes reseau configurees sur la machine.'; Action = { Invoke-Step 'route print' { route print | Out-Host } } } @{ Label = 'Vider le cache ARP'; Desc = 'Efface la table ARP pour corriger des soucis de communication locale.'; Action = { Invoke-Step 'Vider le cache ARP' { netsh interface ip delete arpcache } -Confirm } } @{ Label = 'Reset du proxy WinHTTP'; Desc = 'Supprime un proxy systeme qui bloquerait les connexions.'; Action = { Invoke-Step 'netsh winhttp reset proxy' { netsh winhttp reset proxy } } } @{ Label = 'Reset Winsock'; Desc = 'Reinitialise le catalogue reseau Winsock (corrige beaucoup de bugs reseau). Redemarrage requis.'; Action = { Invoke-Step 'netsh winsock reset' { netsh winsock reset } -Confirm } } @{ Label = 'Reset de la pile IP'; Desc = 'Remet la configuration TCP/IP a zero. Redemarrage requis.'; Action = { Invoke-Step 'netsh int ip reset' { netsh int ip reset } -Confirm } } @{ Label = 'Reset du pare-feu Windows'; Desc = 'Restaure les regles de pare-feu par defaut.'; Action = { Invoke-Step 'netsh advfirewall reset' { netsh advfirewall reset } -Confirm } } @{ Label = 'Redemarrer les cartes reseau actives'; Desc = 'Coupe et relance les cartes reseau pour effacer un blocage temporaire.'; Action = { Invoke-Step 'Redemarrage des cartes reseau' { Get-NetAdapter | Where-Object Status -eq 'Up' | Restart-NetAdapter -Confirm:$false } -Confirm } } @{ Label = 'Reset reseau COMPLET'; Desc = 'Enchaine flush DNS + Winsock + pile IP + proxy. La solution radicale.'; Action = { Invoke-Step 'Reset reseau complet' { Reset-MehdiNetwork } -Confirm } } ) Invoke-Menu -Title 'RESEAU' -Items $items } function Show-RepairUpdateMenu { $items = @( @{ Label = 'Reset COMPLET de Windows Update'; Desc = 'Repare Windows Update en reinitialisant ses services et caches (erreurs de MAJ).'; Action = { Invoke-Step 'Reset Windows Update' { Reset-MehdiWindowsUpdate } -Confirm } } @{ Label = 'Vider le cache des mises a jour'; Desc = 'Supprime les fichiers de MAJ telecharges, souvent a l''origine des blocages.'; Action = { Invoke-Step 'Vider cache Windows Update' { Stop-Service wuauserv -Force -ErrorAction SilentlyContinue $sd = Join-Path $env:windir 'SoftwareDistribution\Download' if (Test-Path $sd) { Get-ChildItem $sd -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue } Start-Service wuauserv -ErrorAction SilentlyContinue Write-Host ' Cache vide.' } -Confirm } } @{ Label = 'Rechercher les mises a jour'; Desc = 'Declenche une recherche de MAJ en arriere-plan (usoclient).'; Action = { Invoke-Step 'Recherche des MAJ' { usoclient StartScan; Write-Host ' Recherche lancee.' } } } @{ Label = 'Installer les mises a jour disponibles'; Desc = 'Lance l''installation des MAJ deja trouvees (usoclient).'; Action = { Invoke-Step 'Installation des MAJ' { usoclient StartInstall; Write-Host ' Installation lancee.' } } } @{ Label = 'Historique des mises a jour installees'; Desc = 'Liste les correctifs (KB) deja installes sur le PC.'; Action = { Invoke-Step 'Historique des MAJ' { Get-HotFix | Sort-Object InstalledOn -Descending | Format-Table HotFixID, Description, InstalledOn -AutoSize | Out-Host } } } @{ Label = 'Ouvrir Windows Update'; Desc = 'Ouvre la page Windows Update des parametres.'; Action = { Invoke-Step 'Windows Update' { Start-Process 'ms-settings:windowsupdate' } } } ) Invoke-Menu -Title 'WINDOWS UPDATE' -Items $items } function Show-RepairStoreMenu { $items = @( @{ Label = 'Reinitialiser le Microsoft Store (wsreset)'; Desc = 'Vide le cache du Store quand il refuse de telecharger ou plante.'; Action = { Invoke-Step 'wsreset' { Start-Process 'wsreset.exe' -Wait } } } @{ Label = 'Reparer le Microsoft Store'; Desc = 'Reenregistre l''application Store si elle est cassee ou absente.'; Action = { Invoke-Step 'Reparer le Store' { Get-AppxPackage -AllUsers Microsoft.WindowsStore | ForEach-Object { Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml" -ErrorAction SilentlyContinue } Write-Host ' Microsoft Store reenregistre.' } -Confirm } } @{ Label = 'Reenregistrer toutes les apps UWP'; Desc = 'Repare le menu Demarrer et les apps integrees qui ne s''ouvrent plus.'; Action = { Invoke-Step 'Reenregistrement apps UWP' { Register-MehdiUwpApps } -Confirm } } ) Invoke-Menu -Title 'MAGASIN & APPLICATIONS' -Items $items } function Show-RepairCleanupMenu { $items = @( @{ Label = 'Vider les fichiers temporaires'; Desc = 'Supprime TEMP et Prefetch pour liberer de l''espace et nettoyer les restes.'; Action = { Invoke-Step 'Nettoyage des fichiers temporaires' { Clear-MehdiTemp } -Confirm } } @{ Label = 'Vider le cache des miniatures'; Desc = 'Regenere les vignettes de l''explorateur si elles sont corrompues.'; Action = { Invoke-Step 'Cache des miniatures' { Remove-Item "$env:LOCALAPPDATA\Microsoft\Windows\Explorer\thumbcache_*.db" -Force -ErrorAction SilentlyContinue; Write-Host ' Cache des miniatures vide.' } -Confirm } } @{ Label = 'Vider le cache des icones'; Desc = 'Corrige les icones affichees de travers ou en blanc.'; Action = { Invoke-Step 'Cache des icones' { Remove-Item "$env:LOCALAPPDATA\IconCache.db" -Force -ErrorAction SilentlyContinue; Write-Host ' Cache des icones vide.' } -Confirm } } @{ Label = 'Vider la corbeille'; Desc = 'Supprime definitivement le contenu de la corbeille.'; Action = { Invoke-Step 'Vider la corbeille' { Clear-RecycleBin -Force -ErrorAction SilentlyContinue } -Confirm } } @{ Label = 'Lancer le Nettoyage de disque'; Desc = 'Ouvre l''outil Windows pour supprimer fichiers inutiles et anciennes MAJ.'; Action = { Invoke-Step 'cleanmgr' { Start-Process 'cleanmgr.exe' } } } ) Invoke-Menu -Title 'NETTOYAGE' -Items $items } function Show-RepairRestoreMenu { $items = @( @{ Label = 'Creer un point de restauration'; Desc = 'Sauvegarde l''etat du systeme avant une manip risquee.'; Action = { Invoke-Step 'Point de restauration' { Checkpoint-Computer -Description "MehdiCore $(Get-Date -Format 'yyyy-MM-dd HH:mm')" -RestorePointType MODIFY_SETTINGS Write-Host ' Point de restauration cree.' } } } @{ Label = 'Activer la protection systeme (C:)'; Desc = 'Active les points de restauration sur le disque systeme (requis pour en creer).'; Action = { Invoke-Step 'Activation protection systeme' { Enable-ComputerRestore -Drive 'C:\' } -Confirm } } @{ Label = 'Lister les points de restauration'; Desc = 'Affiche les points de restauration existants.'; Action = { Invoke-Step 'Points de restauration' { Get-ComputerRestorePoint | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Ouvrir la restauration du systeme'; Desc = 'Lance l''assistant pour revenir a un point anterieur.'; Action = { Invoke-Step 'rstrui' { Start-Process 'rstrui.exe' } } } ) Invoke-Menu -Title 'RESTAURATION SYSTEME' -Items $items } function Show-RepairDiagMenu { $items = @( @{ Label = 'Informations systeme'; Desc = 'Resume complet : OS, materiel, reseau, correctifs (systeminfo).'; Action = { Invoke-Step 'Informations systeme' { systeminfo.exe | Out-Host } } } @{ Label = 'Redemarrage en attente ?'; Desc = 'Indique si Windows attend un redemarrage pour finir une operation.'; Action = { Invoke-Step 'Redemarrage en attente' { if (Test-MehdiPendingReboot) { Write-Host ' OUI - un redemarrage est en attente.' -ForegroundColor Yellow } else { Write-Host ' NON - aucun redemarrage en attente.' -ForegroundColor Green } } } } @{ Label = 'Rapport energie (powercfg /energy)'; Desc = 'Detecte les problemes d''alimentation et de veille (rapport HTML).'; Action = { Invoke-Step 'Rapport energie' { $out = Join-Path ([Environment]::GetFolderPath('Desktop')) 'mehdicore-energy.html' powercfg /energy /output $out /duration 30 Write-Host " Rapport genere : $out" } } } @{ Label = 'Rapport de batterie'; Desc = 'Genere un rapport d''usure et d''autonomie de la batterie (HTML).'; Action = { Invoke-Step 'Rapport de batterie' { $out = Join-Path ([Environment]::GetFolderPath('Desktop')) 'mehdicore-batterie.html' powercfg /batteryreport /output $out Write-Host " Rapport genere : $out" } } } @{ Label = 'Liste des pilotes installes'; Desc = 'Affiche tous les pilotes presents sur le systeme (driverquery).'; Action = { Invoke-Step 'Pilotes' { driverquery | Out-Host } } } @{ Label = 'Processus les plus gourmands (CPU)'; Desc = 'Top 15 des processus consommant le plus de CPU/RAM.'; Action = { Invoke-Step 'Top processus' { Get-Process | Sort-Object CPU -Descending | Select-Object -First 15 Name, Id, @{ n = 'RAM(MB)'; e = { [math]::Round($_.WS / 1MB) } }, CPU | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Erreurs systeme recentes (20)'; Desc = 'Les 20 dernieres erreurs du journal systeme, pour diagnostiquer un plantage.'; Action = { Invoke-Step 'Erreurs systeme' { Get-WinEvent -FilterHashtable @{ LogName = 'System'; Level = 2 } -MaxEvents 20 -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, ProviderName | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Diagnostic memoire au redemarrage'; Desc = 'Programme un test de la memoire RAM au prochain demarrage (mdsched).'; Action = { Invoke-Step 'mdsched' { Start-Process 'mdsched.exe' } -Confirm } } ) Invoke-Menu -Title 'DIAGNOSTICS' -Items $items } function Show-RepairServicesMenu { $items = @( @{ Label = 'Redemarrer l explorateur Windows'; Desc = 'Relance explorer.exe : corrige barre des taches/menu Demarrer figes.'; Action = { Invoke-Step 'Redemarrage de l''explorateur' { Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 1 if (-not (Get-Process -Name explorer -ErrorAction SilentlyContinue)) { Start-Process explorer.exe } Write-Host ' Explorateur redemarre.' } } } @{ Label = 'Reinitialiser le spouleur d impression'; Desc = 'Debloque les impressions en attente et relance le service.'; Action = { Invoke-Step 'Reset spouleur d''impression' { Reset-MehdiPrintSpooler } -Confirm } } @{ Label = 'Redemarrer le service audio'; Desc = 'Relance l''audio quand le son ne fonctionne plus.'; Action = { Invoke-Step 'Redemarrage service audio' { Restart-Service -Name Audiosrv -Force -ErrorAction SilentlyContinue; Write-Host ' Service audio redemarre.' } } } @{ Label = 'Redemarrer le service Windows Update'; Desc = 'Relance wuauserv quand Windows Update est bloque.'; Action = { Invoke-Step 'Redemarrage Windows Update' { Restart-Service wuauserv -Force -ErrorAction SilentlyContinue; Write-Host ' Service redemarre.' } } } @{ Label = 'Lister les services en cours'; Desc = 'Affiche tous les services actuellement en execution.'; Action = { Invoke-Step 'Services actifs' { Get-Service | Where-Object Status -eq 'Running' | Sort-Object DisplayName | Format-Table Status, Name, DisplayName -AutoSize | Out-Host } } } @{ Label = 'Ouvrir la console des services'; Desc = 'Ouvre services.msc pour gerer les services manuellement.'; Action = { Invoke-Step 'services.msc' { Start-Process 'services.msc' } } } @{ Label = 'Ouvrir le gestionnaire des taches'; Desc = 'Ouvre le Gestionnaire des taches Windows.'; Action = { Invoke-Step 'Gestionnaire des taches' { Start-Process 'taskmgr.exe' } } } ) Invoke-Menu -Title 'SERVICES & INTERFACE' -Items $items } function Show-RepairMenu { $items = @( @{ Label = 'Integrite systeme (SFC / DISM)'; Desc = 'Reparer les fichiers et l''image de Windows.'; Action = { Show-RepairIntegrityMenu } } @{ Label = 'Disque (CHKDSK / SMART / defrag)'; Desc = 'Analyser, reparer et optimiser les disques.'; Action = { Show-RepairDiskMenu } } @{ Label = 'Reseau'; Desc = 'Reparer la connexion et la configuration reseau.'; Action = { Show-RepairNetworkMenu } } @{ Label = 'Windows Update'; Desc = 'Reparer et piloter les mises a jour.'; Action = { Show-RepairUpdateMenu } } @{ Label = 'Magasin & applications'; Desc = 'Reparer le Store et les apps integrees.'; Action = { Show-RepairStoreMenu } } @{ Label = 'Nettoyage'; Desc = 'Liberer de l''espace et vider les caches.'; Action = { Show-RepairCleanupMenu } } @{ Label = 'Restauration systeme'; Desc = 'Points de restauration et retour arriere.'; Action = { Show-RepairRestoreMenu } } @{ Label = 'Diagnostics'; Desc = 'Rapports et infos pour identifier un probleme.'; Action = { Show-RepairDiagMenu } } @{ Label = 'Services & interface'; Desc = 'Relancer explorateur, spouleur, audio, services.'; Action = { Show-RepairServicesMenu } } ) Invoke-Menu -Title 'REPARATION SYSTEME' -Items $items } # ---- modules/tweaks.ps1 ---- # ============================================================ # MehdiCore - modules/tweaks.ps1 # Module 2 : Tweaks & confidentialite (avec descriptions) # ============================================================ $script:ExplorerAdvanced = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced' $script:ClassicMenuKey = 'HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}' function Show-TweaksConfidentialiteMenu { $items = @( @{ Label = 'Desactiver la telemetrie'; Desc = 'Coupe l''envoi de donnees de diagnostic a Microsoft (+ service DiagTrack).'; Action = { Invoke-Step 'Desactiver la telemetrie' { Set-MehdiReg 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' 'AllowTelemetry' 0 Set-Service -Name DiagTrack -StartupType Disabled -ErrorAction SilentlyContinue Stop-Service -Name DiagTrack -Force -ErrorAction SilentlyContinue Write-Host ' Telemetrie desactivee.' } -Confirm } } @{ Label = 'Desactiver Cortana'; Desc = 'Desactive l''assistant Cortana et son indexation.'; Action = { Invoke-Step 'Desactiver Cortana' { Set-MehdiReg 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search' 'AllowCortana' 0; Write-Host ' Cortana desactivee.' } -Confirm } } @{ Label = 'Desactiver Windows Copilot'; Desc = 'Retire l''assistant IA Copilot de la barre des taches.'; Action = { Invoke-Step 'Desactiver Copilot' { Set-MehdiReg 'HKCU:\SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot' 'TurnOffWindowsCopilot' 1; Write-Host ' Copilot desactive.' } -Confirm } } @{ Label = 'Desactiver l identifiant de publicite'; Desc = 'Empeche le ciblage publicitaire base sur ton activite.'; Action = { Invoke-Step 'Desactiver la pub ciblee' { Set-MehdiReg 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\AdvertisingInfo' 'Enabled' 0; Write-Host ' Identifiant de publicite desactive.' } -Confirm } } @{ Label = 'Desactiver le suivi de localisation'; Desc = 'Refuse l''acces a la position geographique au niveau systeme.'; Action = { Invoke-Step 'Desactiver la localisation' { Set-MehdiReg 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location' 'Value' 'Deny' 'String'; Write-Host ' Localisation desactivee.' } -Confirm } } @{ Label = 'Desactiver les suggestions du menu Demarrer'; Desc = 'Supprime les apps suggerees et pubs dans le menu Demarrer.'; Action = { Invoke-Step 'Desactiver les suggestions' { Set-MehdiReg 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' 'SystemPaneSuggestionsEnabled' 0; Write-Host ' Suggestions desactivees.' } -Confirm } } ) Invoke-Menu -Title 'CONFIDENTIALITE' -Items $items } function Show-TweaksUpdateMenu { $items = @( @{ Label = 'Desactiver les mises a jour Windows'; Desc = 'Stoppe le service de MAJ (a reactiver pour retrouver les MAJ).'; Action = { Invoke-Step 'Desactiver Windows Update' { Set-Service -Name wuauserv -StartupType Disabled -ErrorAction SilentlyContinue; Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue; Write-Host ' Service Windows Update desactive.' } -Confirm } } @{ Label = 'Reactiver les mises a jour Windows'; Desc = 'Remet le service de MAJ en marche.'; Action = { Invoke-Step 'Reactiver Windows Update' { Set-Service -Name wuauserv -StartupType Manual -ErrorAction SilentlyContinue; Start-Service -Name wuauserv -ErrorAction SilentlyContinue; Write-Host ' Service Windows Update reactive.' } -Confirm } } @{ Label = 'Desactiver le redemarrage auto apres MAJ'; Desc = 'Evite les redemarrages surprises quand une session est ouverte.'; Action = { Invoke-Step 'Pas de redemarrage auto' { Set-MehdiReg 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' 'NoAutoRebootWithLoggedOnUsers' 1; Write-Host ' Redemarrage automatique desactive.' } -Confirm } } @{ Label = 'Desactiver le partage P2P des MAJ'; Desc = 'Empeche Windows d''envoyer tes MAJ a d''autres PC (economise la bande passante).'; Action = { Invoke-Step 'Desactiver le P2P des MAJ' { Set-MehdiReg 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DeliveryOptimization' 'DODownloadMode' 0; Write-Host ' Partage P2P des MAJ desactive.' } -Confirm } } ) Invoke-Menu -Title 'MISES A JOUR' -Items $items } function Show-TweaksInterfaceMenu { $items = @( @{ Label = 'Afficher les extensions de fichiers'; Desc = 'Montre .exe, .pdf, etc. - utile pour reperer les fichiers piegees.'; Action = { Invoke-Step 'Afficher les extensions' { Set-MehdiReg $script:ExplorerAdvanced 'HideFileExt' 0; Restart-MehdiExplorer; Write-Host ' Extensions affichees.' } } } @{ Label = 'Afficher les fichiers caches'; Desc = 'Rend visibles les fichiers et dossiers caches.'; Action = { Invoke-Step 'Afficher les fichiers caches' { Set-MehdiReg $script:ExplorerAdvanced 'Hidden' 1; Restart-MehdiExplorer; Write-Host ' Fichiers caches affiches.' } } } @{ Label = 'Activer le mode sombre'; Desc = 'Applique le theme sombre aux apps et au systeme.'; Action = { Invoke-Step 'Mode sombre' { $p='HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize'; Set-MehdiReg $p 'AppsUseLightTheme' 0; Set-MehdiReg $p 'SystemUsesLightTheme' 0; Restart-MehdiExplorer; Write-Host ' Mode sombre active.' } } } @{ Label = 'Activer le mode clair'; Desc = 'Revient au theme clair pour les apps et le systeme.'; Action = { Invoke-Step 'Mode clair' { $p='HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize'; Set-MehdiReg $p 'AppsUseLightTheme' 1; Set-MehdiReg $p 'SystemUsesLightTheme' 1; Restart-MehdiExplorer; Write-Host ' Mode clair active.' } } } @{ Label = 'Menu contextuel classique (Windows 11)'; Desc = 'Retrouve le clic droit complet de Windows 10 sur Windows 11.'; Action = { Invoke-Step 'Menu contextuel classique' { New-Item -Path "$($script:ClassicMenuKey)\InprocServer32" -Force | Out-Null; Set-ItemProperty -Path "$($script:ClassicMenuKey)\InprocServer32" -Name '(Default)' -Value '' -Force; Restart-MehdiExplorer; Write-Host ' Menu contextuel classique active.' } -Confirm } } @{ Label = 'Restaurer le menu contextuel Windows 11'; Desc = 'Annule le tweak precedent et remet le clic droit Windows 11.'; Action = { Invoke-Step 'Restaurer menu Windows 11' { Remove-Item -Path $script:ClassicMenuKey -Recurse -Force -ErrorAction SilentlyContinue; Restart-MehdiExplorer; Write-Host ' Menu Windows 11 restaure.' } -Confirm } } @{ Label = 'Ne jamais grouper la barre des taches (Win10)'; Desc = 'Affiche un bouton par fenetre avec son titre, sans regroupement.'; Action = { Invoke-Step 'Degrouper la barre des taches' { Set-MehdiReg $script:ExplorerAdvanced 'TaskbarGlomLevel' 2; Restart-MehdiExplorer; Write-Host ' Barre des taches degroupee.' } } } @{ Label = 'Ouvrir l explorateur sur Ce PC'; Desc = 'L''explorateur s''ouvre sur Ce PC au lieu d''Acces rapide.'; Action = { Invoke-Step 'Explorateur sur Ce PC' { Set-MehdiReg $script:ExplorerAdvanced 'LaunchTo' 1; Restart-MehdiExplorer; Write-Host ' Explorateur ouvre sur Ce PC.' } } } @{ Label = 'Desactiver la recherche Bing du menu Demarrer'; Desc = 'Supprime les resultats web Bing de la recherche Windows.'; Action = { Invoke-Step 'Desactiver Bing' { Set-MehdiReg 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Search' 'BingSearchEnabled' 0; Restart-MehdiExplorer; Write-Host ' Recherche Bing desactivee.' } } } @{ Label = 'Aligner la barre des taches a gauche (Win11)'; Desc = 'Replace les icones de la barre des taches a gauche, facon Windows 10.'; Action = { Invoke-Step 'Barre des taches a gauche' { Set-MehdiReg $script:ExplorerAdvanced 'TaskbarAl' 0; Restart-MehdiExplorer; Write-Host ' Barre des taches alignee a gauche.' } } } ) Invoke-Menu -Title 'INTERFACE' -Items $items } function Show-TweaksMenu { $items = @( @{ Label = 'Confidentialite'; Desc = 'Telemetrie, Cortana, Copilot, pub, localisation.'; Action = { Show-TweaksConfidentialiteMenu } } @{ Label = 'Mises a jour Windows'; Desc = 'Activer/desactiver et configurer Windows Update.'; Action = { Show-TweaksUpdateMenu } } @{ Label = 'Interface'; Desc = 'Extensions, mode sombre, menus, barre des taches.'; Action = { Show-TweaksInterfaceMenu } } ) Invoke-Menu -Title 'TWEAKS & CONFIDENTIALITE' -Items $items } # ---- modules/performance.ps1 ---- # ============================================================ # MehdiCore - modules/performance.ps1 # Module : Performance & nettoyage avance (avec descriptions) # ============================================================ function Enable-MehdiUltimatePower { $out = powercfg -duplicatescheme e9a42b02-d5df-448d-aa00-03f14749eb61 2>&1 $guid = ([regex]::Match(($out -join ' '), '[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}')).Value if ($guid) { powercfg /setactive $guid; Write-Host " Plan 'Performances ultimes' active." } else { Write-Host ' Plan deja present ou non disponible sur cette edition.' } } function Remove-MehdiBloatware { $bloat = @( 'Microsoft.3DBuilder', 'Microsoft.BingWeather', 'Microsoft.GetHelp', 'Microsoft.Getstarted', 'Microsoft.MicrosoftSolitaireCollection', 'Microsoft.People', 'Microsoft.WindowsFeedbackHub', 'Microsoft.XboxApp', 'Microsoft.XboxGamingOverlay', 'Microsoft.ZuneMusic', 'Microsoft.ZuneVideo', 'Microsoft.SkypeApp', 'Microsoft.MicrosoftOfficeHub', 'Microsoft.Microsoft3DViewer', 'king.com.CandyCrushSaga', 'Microsoft.MixedReality.Portal' ) foreach ($b in $bloat) { Get-AppxPackage -Name $b -AllUsers -ErrorAction SilentlyContinue | Remove-AppxPackage -ErrorAction SilentlyContinue } Write-Host ' Applications preinstallees ciblees supprimees (si presentes).' } function Remove-MehdiWindowsOld { if (Test-Path 'C:\Windows.old') { cmd /c 'takeown /f C:\Windows.old /r /d Y >nul 2>&1' cmd /c 'icacls C:\Windows.old /grant *S-1-5-32-544:F /t /c >nul 2>&1' cmd /c 'rmdir /s /q C:\Windows.old' if (Test-Path 'C:\Windows.old') { Write-Host ' Suppression partielle - relancer apres redemarrage si besoin.' } else { Write-Host ' Windows.old supprime.' } } else { Write-Host ' Aucun dossier C:\Windows.old.' } } function Show-PerformanceMenu { $items = @( @{ Label = 'Plan d alimentation Performances ultimes'; Desc = 'Debride le CPU au maximum (ideal PC fixe branche au secteur).'; Action = { Invoke-Step 'Performances ultimes' { Enable-MehdiUltimatePower } -Confirm } } @{ Label = 'Plan Haute performance'; Desc = 'Active le plan rapide standard, disponible sur toutes les editions.'; Action = { Invoke-Step 'Plan Haute performance' { powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c; Write-Host ' Plan Haute performance active.' } -Confirm } } @{ Label = 'Ajuster les effets visuels pour la performance'; Desc = 'Coupe les animations Windows pour gagner en fluidite (vieux PC).'; Action = { Invoke-Step 'Effets visuels (performance)' { Set-MehdiReg 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VisualEffects' 'VisualFXSetting' 2; Write-Host ' Effets visuels regles sur la performance (rouvrir la session).' } -Confirm } } @{ Label = 'Desactiver la mise en veille'; Desc = 'Empeche le PC de se mettre en veille (secteur + batterie).'; Action = { Invoke-Step 'Desactiver la veille' { powercfg /change standby-timeout-ac 0; powercfg /change standby-timeout-dc 0; powercfg /change hibernate-timeout-ac 0; powercfg /change hibernate-timeout-dc 0; Write-Host ' Mise en veille desactivee.' } -Confirm } } @{ Label = 'Desactiver l hibernation'; Desc = 'Supprime hiberfil.sys et libere plusieurs Go d''espace disque.'; Action = { Invoke-Step 'Desactiver hibernation' { powercfg /h off; Write-Host ' Hibernation desactivee.' } -Confirm } } @{ Label = 'Desactiver le demarrage rapide'; Desc = 'Corrige des soucis d''arret/redemarrage et de double-boot.'; Action = { Invoke-Step 'Desactiver demarrage rapide' { Set-MehdiReg 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power' 'HiberbootEnabled' 0; Write-Host ' Demarrage rapide desactive.' } -Confirm } } @{ Label = 'Desactiver SysMain (Superfetch)'; Desc = 'Reduit l''usage disque a 100% sur certains PC (surtout HDD).'; Action = { Invoke-Step 'Desactiver SysMain' { Set-Service -Name SysMain -StartupType Disabled -ErrorAction SilentlyContinue; Stop-Service -Name SysMain -Force -ErrorAction SilentlyContinue; Write-Host ' SysMain desactive.' } -Confirm } } @{ Label = 'Desactiver l indexation (Windows Search)'; Desc = 'Soulage le disque mais ralentit la recherche de fichiers (compromis).'; Action = { Invoke-Step 'Desactiver l indexation' { Set-Service -Name WSearch -StartupType Disabled -ErrorAction SilentlyContinue; Stop-Service -Name WSearch -Force -ErrorAction SilentlyContinue; Write-Host ' Indexation desactivee.' } -Confirm } } @{ Label = 'Gerer les programmes au demarrage'; Desc = 'Ouvre la liste des apps lancees au demarrage pour les desactiver.'; Action = { Invoke-Step 'Programmes au demarrage' { Start-Process 'ms-settings:startupapps' } } } @{ Label = 'Supprimer les applications preinstallees (debloat)'; Desc = 'Desinstalle les apps inutiles preinstallees par Microsoft.'; Action = { Invoke-Step 'Debloat' { Remove-MehdiBloatware } -Confirm } } @{ Label = 'Vider tous les journaux d evenements'; Desc = 'Efface les journaux Windows (utile apres diagnostic ou pour repartir propre).'; Action = { Invoke-Step 'Vider les journaux' { wevtutil el | ForEach-Object { wevtutil cl "$_" 2>$null }; Write-Host ' Journaux d''evenements vides.' } -Confirm } } @{ Label = 'Supprimer le dossier Windows.old'; Desc = 'Recupere l''espace de l''ancienne installation apres une mise a niveau.'; Action = { Invoke-Step 'Supprimer Windows.old' { Remove-MehdiWindowsOld } -Confirm } } ) Invoke-Menu -Title 'PERFORMANCE & NETTOYAGE AVANCE' -Items $items } # ---- modules/sysinfo.ps1 ---- # ============================================================ # MehdiCore - modules/sysinfo.ps1 # Module : Systeme & informations (lecture seule, descriptions) # ============================================================ function Show-MehdiSpecs { $os = Get-CimInstance Win32_OperatingSystem $cpu = Get-CimInstance Win32_Processor | Select-Object -First 1 $cs = Get-CimInstance Win32_ComputerSystem $gpu = Get-CimInstance Win32_VideoController | Select-Object -First 1 $bb = Get-CimInstance Win32_BaseBoard Write-Host " Machine : $($cs.Manufacturer) $($cs.Model)" Write-Host " OS : $($os.Caption) ($($os.OSArchitecture))" Write-Host " CPU : $($cpu.Name.Trim())" Write-Host " Coeurs : $($cpu.NumberOfCores) / $($cpu.NumberOfLogicalProcessors) threads" Write-Host " RAM : $([math]::Round($cs.TotalPhysicalMemory / 1GB, 1)) Go" Write-Host " GPU : $($gpu.Name)" Write-Host " Carte mere : $($bb.Manufacturer) $($bb.Product)" } function Show-MehdiWindowsVersion { $r = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' Write-Host " Produit : $($r.ProductName)" Write-Host " Edition : $($r.EditionID)" Write-Host " Version : $($r.DisplayVersion) (build $($r.CurrentBuild).$($r.UBR))" } function Show-MehdiUptime { $boot = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime $up = (Get-Date) - $boot Write-Host " Dernier demarrage : $boot" Write-Host (" Uptime : {0}j {1}h {2}m" -f $up.Days, $up.Hours, $up.Minutes) } function Show-MehdiWifiPasswords { $lines = netsh wlan show profiles $names = $lines | Where-Object { $_ -match ':' -and $_ -match '(?i)profil|profile' } | ForEach-Object { ($_ -split ':', 2)[1].Trim() } | Where-Object { $_ } if (-not $names) { Write-Host ' Aucun profil Wi-Fi enregistre.'; return } foreach ($n in $names) { $info = netsh wlan show profile name="$n" key=clear $pw = $info | Where-Object { $_ -match '(?i)Key Content|Contenu de la cl' } | ForEach-Object { ($_ -split ':', 2)[1].Trim() } if (-not $pw) { $pw = '(aucun / reseau ouvert)' } Write-Host (" {0,-28} {1}" -f $n, $pw) } } function Show-SystemInfoMenu { $items = @( @{ Label = 'Specifications du PC'; Desc = 'CPU, RAM, GPU, carte mere et modele en un ecran.'; Action = { Invoke-Step 'Specifications' { Show-MehdiSpecs } } } @{ Label = 'Version et build de Windows'; Desc = 'Edition, version (ex. 23H2) et numero de build exact.'; Action = { Invoke-Step 'Version de Windows' { Show-MehdiWindowsVersion } } } @{ Label = 'Statut d activation de Windows'; Desc = 'Indique si Windows est active et le type de licence.'; Action = { Invoke-Step 'Activation Windows' { cscript //Nologo "$env:windir\System32\slmgr.vbs" /xpr } } } @{ Label = 'Cle de produit (OEM/BIOS)'; Desc = 'Recupere la cle Windows integree au BIOS (PC de marque).'; Action = { Invoke-Step 'Cle de produit' { $k = (Get-CimInstance -ClassName SoftwareLicensingService).OA3xOriginalProductKey if ($k) { Write-Host " Cle OEM (BIOS) : $k" } else { Write-Host ' Aucune cle OEM dans le BIOS (cle numerique ou retail probable).' } } } } @{ Label = 'Mots de passe Wi-Fi enregistres'; Desc = 'Affiche les cles des reseaux Wi-Fi memorises sur ce PC.'; Action = { Invoke-Step 'Mots de passe Wi-Fi' { Show-MehdiWifiPasswords } } } @{ Label = 'Temps de fonctionnement (uptime)'; Desc = 'Depuis combien de temps le PC tourne sans redemarrage.'; Action = { Invoke-Step 'Uptime' { Show-MehdiUptime } } } @{ Label = 'Configuration reseau complete'; Desc = 'Adresses IP, MAC, passerelle, DNS de toutes les cartes (ipconfig /all).'; Action = { Invoke-Step 'Configuration reseau' { ipconfig /all | Out-Host } } } @{ Label = 'Adresse IP publique'; Desc = 'Affiche l''adresse IP vue depuis Internet.'; Action = { Invoke-Step 'IP publique' { try { Write-Host " IP publique : $((Invoke-RestMethod -Uri 'https://api.ipify.org?format=json').ip)" } catch { Write-Host ' Impossible de recuperer l IP publique.' } } } } @{ Label = 'Liste des programmes installes'; Desc = 'Tous les logiciels installes avec version et editeur.'; Action = { Invoke-Step 'Programmes installes' { $paths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' Get-ItemProperty $paths -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName } | Select-Object DisplayName, DisplayVersion, Publisher | Sort-Object DisplayName | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Comptes utilisateurs locaux'; Desc = 'Liste les comptes du PC et s''ils sont actifs.'; Action = { Invoke-Step 'Comptes locaux' { Get-LocalUser | Format-Table Name, Enabled, LastLogon -AutoSize | Out-Host } } } @{ Label = 'Disques et partitions'; Desc = 'Disques physiques, taille, style (MBR/GPT) et sante.'; Action = { Invoke-Step 'Disques' { Get-Disk | Select-Object Number, FriendlyName, @{ n = 'Taille(GB)'; e = { [math]::Round($_.Size / 1GB) } }, PartitionStyle, HealthStatus | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Variables d environnement'; Desc = 'Affiche toutes les variables systeme et utilisateur (PATH, TEMP, etc.).'; Action = { Invoke-Step 'Variables d environnement' { Get-ChildItem Env: | Sort-Object Name | Format-Table Name, Value -AutoSize | Out-Host } } } ) Invoke-Menu -Title 'SYSTEME & INFORMATIONS' -Items $items } # ---- modules/diagnostics.ps1 ---- # ============================================================ # MehdiCore - modules/diagnostics.ps1 # Module : Diagnostic peripheriques + verification pilotes # Chaque diagnostic = constat + PISTES (tips subtils/fourbes) # ============================================================ # Encadre de pistes / tips a verifier. function Show-MehdiTips { param([Parameter(Mandatory = $true)][string[]]$Tips) Write-Host '' Write-Host ' +-- PISTES A VERIFIER ---------------------------------------' -ForegroundColor Yellow foreach ($t in $Tips) { Write-Host ' | - ' -ForegroundColor Yellow -NoNewline Write-Host $t -ForegroundColor Gray } Write-Host ' +------------------------------------------------------------' -ForegroundColor Yellow } # Traduit un code de probleme du Gestionnaire de peripheriques (CM_PROB_*). function Get-MehdiProblemText { param([int]$Code) switch ($Code) { 1 { 'Peripherique mal configure.' } 3 { 'Pilote corrompu ou memoire insuffisante.' } 9 { 'Informations du peripherique invalides.' } 10 { 'Le peripherique ne peut pas demarrer (souvent un pilote).' } 12 { 'Ressources insuffisantes (conflit IRQ/memoire).' } 14 { 'Un redemarrage est requis.' } 18 { 'Reinstaller les pilotes.' } 19 { 'Cle de registre du peripherique endommagee.' } 21 { 'Windows est en train de supprimer le peripherique.' } 22 { 'Peripherique desactive.' } 24 { 'Peripherique absent, mal branche ou en panne.' } 28 { 'Pilotes non installes.' } 31 { 'Le pilote ne fournit pas les ressources necessaires.' } 32 { 'Le service de demarrage du pilote est desactive.' } 37 { 'Echec de l initialisation du pilote.' } 38 { 'Une instance du pilote est deja chargee en memoire.' } 39 { 'Pilote manquant ou corrompu.' } 40 { 'Informations du service invalides dans le registre.' } 43 { 'Windows a arrete ce peripherique (erreur signalee).' } 44 { 'Une application a arrete ce peripherique.' } 45 { 'Peripherique non connecte actuellement.' } 46 { 'Indisponible (arret du systeme en cours).' } 47 { 'Prepare a l ejection (retrait en toute securite).' } 48 { 'Logiciel bloque pour incompatibilite connue.' } 49 { 'Ruche systeme trop grande (peripheriques fantomes a nettoyer).' } 52 { 'Pilote non signe / signature non verifiable.' } default { "Code de probleme $Code." } } } # Liste les peripheriques dont l'etat n'est pas OK, avec code + cause. function Get-MehdiProblemDevices { $bad = Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.Status -ne 'OK' -and $_.Status -ne 'Unknown' } foreach ($d in $bad) { $code = $null try { $p = Get-PnpDeviceProperty -InstanceId $d.InstanceId -KeyName 'DEVPKEY_Device_ProblemCode' -ErrorAction SilentlyContinue if ($p -and $p.Data) { $code = [int]$p.Data } } catch { } $cause = '' if ($code) { $cause = Get-MehdiProblemText $code } [pscustomobject]@{ Nom = $d.FriendlyName Classe = $d.Class Etat = $d.Status Code = $code Cause = $cause } } } # Etat de la confidentialite (micro/camera) au niveau machine + utilisateur. function Get-MehdiPrivacyConsent { param([Parameter(Mandatory = $true)][string]$Capability) $paths = [ordered]@{ 'Machine (toutes apps)' = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\$Capability" 'Utilisateur' = "HKCU:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\$Capability" } $result = [ordered]@{} foreach ($k in $paths.Keys) { $v = (Get-ItemProperty -Path $paths[$k] -Name Value -ErrorAction SilentlyContinue).Value if ($v) { $result[$k] = $v } else { $result[$k] = '(non defini)' } } return $result } # ---- Diagnostics ---- function Invoke-MehdiAudioDiag { Write-Host ' --- Services audio ---' -ForegroundColor Cyan foreach ($s in 'Audiosrv', 'AudioEndpointBuilder') { $svc = Get-Service -Name $s -ErrorAction SilentlyContinue if ($svc) { Write-Host (" {0,-22}: {1}" -f $svc.Name, $svc.Status) } } Write-Host '' Write-Host ' --- Peripheriques audio (entrees/sorties) ---' -ForegroundColor Cyan Get-PnpDevice -Class AudioEndpoint -ErrorAction SilentlyContinue | Select-Object Status, FriendlyName | Format-Table -AutoSize | Out-Host Write-Host ' --- Controleurs / pilotes audio ---' -ForegroundColor Cyan Get-PnpDevice -Class MEDIA -ErrorAction SilentlyContinue | Select-Object Status, FriendlyName | Format-Table -AutoSize | Out-Host Write-Host ' --- Confidentialite micro ---' -ForegroundColor Cyan $consent = Get-MehdiPrivacyConsent 'microphone' foreach ($k in $consent.Keys) { Write-Host (" {0,-22}: {1}" -f $k, $consent[$k]) } Show-MehdiTips @( 'Mauvais peripherique par defaut : un casque/HDMI debranche peut rester "par defaut". Verifie aussi le "Peripherique de COMMUNICATION par defaut", souvent different.', 'Mode exclusif : Proprietes du micro > Avance > decoche "Autoriser les applications a prendre le controle exclusif" (une appli peut monopoliser le micro).', 'Niveaux : Proprietes > Niveaux : "Microphone" a 0, ou "Amplification du micro" (boost) a 0 alors que le volume parait correct.', 'Permission PAR appli : Parametres > Confidentialite > Microphone : le global peut etre OK mais coupe pour UNE seule appli.', '"Autoriser les applications de bureau a acceder au micro" est un reglage SEPARE (tout en bas de la page) des apps du Store.', 'Pilote generique : si le pilote Realtek/constructeur a ete remplace par un pilote Microsoft generique, des entrees (jack avant) disparaissent.', 'Detection de prise : le gestionnaire Realtek peut avoir desactive la detection auto des jacks -> prise avant inactive.', 'Micro USB : la veille selective USB le coupe (Gestionnaire > hub USB > Gestion de l alimentation).', 'Une autre appli (Teams, Discord, OBS) garde le micro ouvert : ferme-la, ou regarde l icone micro dans la barre des taches.', 'Antivirus "protection du micro" ou GPO entreprise peut bloquer l acces independamment de Windows.' ) } function Invoke-MehdiWebcamDiag { Write-Host ' --- Cameras ---' -ForegroundColor Cyan Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.Class -in @('Camera', 'Image') -or $_.FriendlyName -match 'cam' } | Select-Object Status, Class, FriendlyName | Format-Table -AutoSize | Out-Host Write-Host ' --- Confidentialite camera ---' -ForegroundColor Cyan $consent = Get-MehdiPrivacyConsent 'webcam' foreach ($k in $consent.Keys) { Write-Host (" {0,-22}: {1}" -f $k, $consent[$k]) } Show-MehdiTips @( 'Cache physique / obturateur ferme, ou raccourci clavier (Fn) qui coupe la camera.', 'Permission PAR appli : Parametres > Confidentialite > Camera, possiblement coupee pour une seule appli.', '"Autoriser les applications de bureau a acceder a la camera" est un reglage distinct, en bas de page.', 'Une seule appli a la fois : beaucoup de webcams refusent 2 applis en meme temps (ferme Teams/Zoom avant de tester).', 'Capteur IR (Windows Hello) et webcam RGB sont 2 peripheriques distincts : l un peut marcher et pas l autre.', 'Antivirus "Webcam shield" (ESET/Kaspersky) ou reglage Lenovo/Dell qui desactive la camera au niveau BIOS/firmware.' ) } function Invoke-MehdiUsbDiag { Write-Host ' --- Peripheriques USB ---' -ForegroundColor Cyan Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.InstanceId -like 'USB*' } | Select-Object Status, FriendlyName | Sort-Object Status | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Veille selective USB : Gestionnaire > hub USB > Gestion de l alimentation > decoche "Autoriser l ordinateur a eteindre ce peripherique".', 'Teste un AUTRE port (de preference a l arriere, sur la carte mere) ; evite les hubs non alimentes pour les disques.', 'Cable "charge seulement" : il alimente mais ne transmet pas de donnees. Teste un autre cable.', 'Alimentation : un disque gourmand sur un hub non alimente decroche (code 43). Branche-le en direct.', 'Code 43 toujours au meme port = port/controleur defaillant ; code 43 partout = pilote du peripherique.', 'Demarrage rapide (Fast Startup) laisse parfois l USB dans un etat instable : un VRAI redemarrage le reinitialise.' ) } function Invoke-MehdiProblemDevicesDiag { Write-Host ' --- Peripheriques en erreur ---' -ForegroundColor Cyan $bad = @(Get-MehdiProblemDevices) if ($bad.Count -eq 0) { Write-Host ' Aucun peripherique en erreur. Tout est OK.' -ForegroundColor Green } else { $bad | Format-Table Nom, Classe, Etat, Code, Cause -AutoSize -Wrap | Out-Host } Show-MehdiTips @( 'Peripheriques "fantomes" : des appareils debranches restent caches. Gestionnaire > Affichage > "Afficher les peripheriques caches" pour les voir/supprimer.', 'Code 28 (pilote manquant) : laisse Windows Update chercher, ou installe le pilote constructeur (chipset en premier).', 'Code 43 : desinstalle le peripherique (coche "supprimer le pilote") puis "Rechercher les modifications materielles".', 'Code 52 (non signe) : pilote bloque par l integrite du code ; recupere une version signee chez le constructeur.', 'Un "?" sur "Peripherique PCI/ACPI inconnu" = pilote chipset manquant (pack chipset Intel/AMD).' ) } function Invoke-MehdiDriverDiag { Write-Host ' --- Pilotes signes (les plus anciens en tete) ---' -ForegroundColor Cyan $drivers = Get-CimInstance Win32_PnPSignedDriver -ErrorAction SilentlyContinue | Where-Object { $_.DriverDate -and $_.DeviceName } | Select-Object DeviceName, @{ n = 'Version'; e = { $_.DriverVersion } }, @{ n = 'Date'; e = { try { ([datetime]$_.DriverDate).ToString('yyyy-MM-dd') } catch { '' } } }, @{ n = '_d'; e = { try { [datetime]$_.DriverDate } catch { Get-Date } } }, @{ n = 'Fournisseur'; e = { $_.DriverProviderName } } $drivers | Sort-Object _d | Select-Object DeviceName, Version, Date, Fournisseur -First 25 | Format-Table -AutoSize | Out-Host $old = @($drivers | Where-Object { $_._d -lt (Get-Date).AddYears(-5) }) Write-Host '' Write-Host (" Pilotes de plus de 5 ans : {0}" -f $old.Count) -ForegroundColor DarkYellow Show-MehdiTips @( '"A jour" selon Windows Update n est PAS la derniere version constructeur : pour le GPU, passe par NVIDIA/AMD/Intel directement.', 'Un pilote ancien n est pas forcement un probleme : beaucoup de pilotes "inbox" Windows sont stables et ne bougent jamais.', 'Fournisseur "Microsoft" sur GPU/chipset/audio = pilote generique : installe le vrai pilote constructeur pour toutes les fonctions.', 'PC fraichement installe : installe le CHIPSET en premier, puis GPU/audio/reseau.', 'Avant un format, sauvegarde tes pilotes : pnputil /export-driver * C:\Pilotes exporte tous les pilotes tiers.', 'Souci apres une mise a jour : "Restaurer le pilote precedent" (Gestionnaire > Proprietes > Pilote) revient a la version qui marchait.' ) } function Invoke-MehdiNetDeviceDiag { Write-Host ' --- Cartes reseau ---' -ForegroundColor Cyan Get-NetAdapter -ErrorAction SilentlyContinue | Select-Object Name, InterfaceDescription, Status, LinkSpeed, MacAddress | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Wi-Fi qui tombe apres la veille : la veille selective coupe la carte (Proprietes carte > Gestion de l alimentation > decoche l economie).', 'Debit bride : une carte Gigabit qui negocie a 100 Mbps = cable abime (une paire coupee). Teste un autre cable.', 'Adaptateurs virtuels (VPN, Hyper-V, VirtualBox) qui prennent la main : desactive les cartes inutiles.', 'Pilote Wi-Fi generique = deconnexions : installe le pilote constructeur (Intel/Realtek/Killer).', 'Mode avion active par une touche Fn, ou service "Gestion des radios" arrete.', '"Connecte sans Internet" : passe par Reparation > Reseau (flush DNS + reset Winsock + reset IP).' ) } function Invoke-MehdiDisplayDiag { Write-Host ' --- Cartes graphiques ---' -ForegroundColor Cyan Get-CimInstance Win32_VideoController -ErrorAction SilentlyContinue | Select-Object Name, @{ n = 'Pilote'; e = { $_.DriverVersion } }, @{ n = 'Date'; e = { try { ([datetime]$_.DriverDate).ToString('yyyy-MM-dd') } catch { '' } } }, @{ n = 'Resolution'; e = { "$($_.CurrentHorizontalResolution)x$($_.CurrentVerticalResolution)" } } | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'PC portable a 2 GPU : un jeu peut tourner sur l Intel integre au lieu du GPU dedie (Parametres > Affichage > Graphismes, par appli).', 'Ecran bloque a 60 Hz : le taux se regle dans Parametres > Affichage > Avance ; un vieux cable HDMI limite aussi le rafraichissement.', 'Tour avec GPU dedie : branche l ecran sur la CARTE (en bas), surtout pas sur la sortie de la carte mere.', 'La RAM video affichee par WMI est fausse au-dela de 4 Go : ce n est pas une panne.', '"Microsoft Basic Display Adapter" = le vrai pilote GPU a lache : reinstalle proprement (DDU puis pilote constructeur).', 'Scintillement/artefacts : teste un autre cable ET un autre port avant de suspecter le GPU.' ) } function Invoke-MehdiDeviceReport { $bad = @(Get-MehdiProblemDevices) Write-Host ' === RAPPORT PERIPHERIQUES ===' -ForegroundColor Cyan Write-Host '' Write-Host (" Peripheriques en erreur : {0}" -f $bad.Count) if ($bad.Count) { $bad | Format-Table Nom, Etat, Code, Cause -AutoSize -Wrap | Out-Host } $audio = (Get-Service Audiosrv -ErrorAction SilentlyContinue).Status Write-Host (" Service audio (Audiosrv) : {0}" -f $audio) Write-Host (" Confidentialite micro : {0}" -f (Get-MehdiPrivacyConsent 'microphone')['Machine (toutes apps)']) Write-Host (" Confidentialite camera : {0}" -f (Get-MehdiPrivacyConsent 'webcam')['Machine (toutes apps)']) $gpu = (Get-CimInstance Win32_VideoController -ErrorAction SilentlyContinue | Select-Object -First 1).Name Write-Host (" GPU principal : {0}" -f $gpu) } function Invoke-MehdiBatteryDiag { Write-Host ' --- Batterie ---' -ForegroundColor Cyan $b = Get-CimInstance Win32_Battery -ErrorAction SilentlyContinue if ($b) { $b | Select-Object @{n='Charge %';e={$_.EstimatedChargeRemaining}}, @{n='Sur secteur';e={ if($_.BatteryStatus -eq 2){'oui'}else{'non'} }} | Format-Table -AutoSize | Out-Host } else { Write-Host ' Aucune batterie (poste fixe ?).' -ForegroundColor DarkGray } Write-Host ' --- Dernier reveil du PC ---' -ForegroundColor Cyan powercfg /lastwake Write-Host '' Write-Host ' --- Ce qui peut reveiller le PC ---' -ForegroundColor Cyan powercfg /devicequery wake_armed Write-Host '' Write-Host ' --- Ce qui empeche la mise en veille ---' -ForegroundColor Cyan powercfg /requests Show-MehdiTips @( 'PC qui se reveille seul la nuit : un peripherique arme (souris, carte reseau Magic Packet) ou une tache planifiee. Voir la liste ci-dessus.', 'La carte reseau reveille souvent le PC : Gestionnaire > carte > Gestion de l alimentation > decoche "Autoriser ce peripherique a sortir l ordinateur de veille".', 'Veille qui ne tient pas / batterie qui se vide en veille : Modern Standby (S0). Verifie avec : powercfg /a.', 'Une appli (navigateur, jeu, video) peut empecher la veille : elle apparait dans "ce qui empeche la mise en veille".' ) } function Invoke-MehdiBatteryReport { $out = Join-Path ([Environment]::GetFolderPath('Desktop')) 'MehdiCore-batterie.html' Write-Host ' Generation du rapport de batterie (usure, cycles)...' -ForegroundColor Cyan powercfg /batteryreport /output $out | Out-Null if (Test-Path $out) { Start-Process $out Write-Host " Rapport ouvert : $out" -ForegroundColor Green } else { Write-Host ' Impossible de generer le rapport (pas de batterie ?).' -ForegroundColor DarkGray } Show-MehdiTips @( 'Compare DESIGN CAPACITY et FULL CHARGE CAPACITY : l ecart = l usure reelle de la batterie.', 'Une batterie a 60 % de sa capacite d origine se decharge vite : c est de l usure normale, pas un bug logiciel.', 'La section Battery life estimates montre l autonomie qui fond au fil du temps.' ) } function Invoke-MehdiBluetoothDiag { Write-Host ' --- Service Bluetooth ---' -ForegroundColor Cyan $svc = Get-Service bthserv -ErrorAction SilentlyContinue if ($svc) { Write-Host (" bthserv : {0} (demarrage {1})" -f $svc.Status, $svc.StartType) } else { Write-Host ' Pas de service Bluetooth (pas de materiel BT ?).' -ForegroundColor DarkGray } Write-Host '' Write-Host ' --- Peripheriques Bluetooth ---' -ForegroundColor Cyan Get-PnpDevice -Class Bluetooth -ErrorAction SilentlyContinue | Select-Object Status, FriendlyName | Sort-Object Status | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Service de prise en charge Bluetooth (bthserv) arrete = plus aucun appairage. Mets-le en Automatique.', 'Mode avion ou touche Fn radio coupe le Bluetooth sans prevenir.', 'Casque/souris deja appaire a un telephone ou un autre PC : beaucoup d appareils ne tiennent qu UNE connexion a la fois.', 'Pile faible : une souris/casque BT presque a plat se deconnecte alors que c est juste la batterie.', 'Interference USB 3.0 : un dongle BT colle a un port USB3 ou a un disque externe grésille. Rallonge-le ou change de port.', 'Apres une grosse MAJ Windows, supprime l appareil et reappaire-le : l appairage casse souvent.' ) } function Invoke-MehdiPrinterDiag { Write-Host ' --- Spouleur d impression ---' -ForegroundColor Cyan $sp = Get-Service Spooler -ErrorAction SilentlyContinue if ($sp) { Write-Host (" Spooler : {0}" -f $sp.Status) } Write-Host '' Write-Host ' --- Imprimantes ---' -ForegroundColor Cyan Get-CimInstance Win32_Printer -ErrorAction SilentlyContinue | Select-Object Name, @{n='Defaut';e={$_.Default}}, @{n='HorsConnexion';e={$_.WorkOffline}}, PortName | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Utiliser l imprimante hors connexion coche : elle reste grisee meme allumee. Decoche-le (clic droit > Voir les travaux).', 'File bloquee : un document coince stoppe tout. Vide la file ou redemarre le spouleur (module Reparation).', 'Imprimante reseau en WSD : son IP change et le port casse. Cree un port TCP/IP fixe avec l IP de l imprimante.', 'Windows change l imprimante par defaut tout seul : desactive Laisser Windows gerer mon imprimante par defaut.', 'Reseau en Public : le pare-feu bloque l imprimante du reseau local. Passe le reseau en Prive.', 'Imprimante en veille profonde : elle met du temps a repondre et parait hors ligne au premier essai.' ) } function Invoke-MehdiPerfDiag { $os = Get-CimInstance Win32_OperatingSystem Write-Host (" Demarre depuis : {0}" -f $os.LastBootUpTime) -ForegroundColor Cyan Write-Host '' Write-Host ' --- Top 8 processus (CPU cumule) ---' -ForegroundColor Cyan Get-Process | Sort-Object CPU -Descending | Select-Object -First 8 Name, Id, @{n='CPU(s)';e={ if($_.CPU){[math]::Round($_.CPU,0)}else{0} }}, @{n='RAM(MB)';e={[math]::Round($_.WorkingSet64/1MB)}} | Format-Table -AutoSize | Out-Host Write-Host ' --- Top 6 processus (RAM) ---' -ForegroundColor Cyan Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 6 Name, Id, @{n='RAM(MB)';e={[math]::Round($_.WorkingSet64/1MB)}} | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Disque a 100 % apres le demarrage : laisse 5-10 min (indexation, SysMain). Si c est permanent sur un HDD, verifie le SMART (Reparation > Disque).', 'Un processus inconnu qui mange le CPU en continu = potentiel malware/mineur : note son nom, cherche-le, et lance un scan (module Securite).', 'Demarrage rapide masque les vrais redemarrages : si Demarre depuis est tres ancien alors que tu eteins chaque soir, fais un VRAI redemarrage.', 'Trop de programmes au demarrage ralentissent l ouverture de session (module Performance pour les desactiver).', 'PC qui rame puis ralentit d un coup = surchauffe (throttling) : ventilateurs encrasses, pate thermique a refaire.', 'Antivirus tiers qui scanne en boucle bloque le disque : verifie son activite avant d accuser le materiel.' ) } function Invoke-MehdiMemoryDiag { Write-Host ' --- Barrettes installees ---' -ForegroundColor Cyan Get-CimInstance Win32_PhysicalMemory -ErrorAction SilentlyContinue | Select-Object @{n='Emplacement';e={$_.DeviceLocator}}, Manufacturer, @{n='Go';e={[math]::Round($_.Capacity/1GB)}}, @{n='MHz';e={$_.Speed}}, PartNumber | Format-Table -AutoSize | Out-Host $os = Get-CimInstance Win32_OperatingSystem Write-Host (" RAM totale : {0} Go | libre : {1} Go" -f [math]::Round($os.TotalVisibleMemorySize/1MB,1), [math]::Round($os.FreePhysicalMemory/1MB,1)) Show-MehdiTips @( 'Deux barrettes de vitesses differentes : tout tourne a la plus lente. Mets des barrettes identiques (kit).', 'RAM bridee : sans profil XMP/EXPO active dans le BIOS, une RAM 3200 MHz tourne souvent a 2133/2400 par defaut.', 'Un seul canal : 2 barrettes dans les mauvais slots (souvent il faut A2/B2) divisent la bande passante. Voir le manuel carte mere.', 'Ecrans bleus aleatoires + plantages sans logique = souvent la RAM. Teste avec l outil ci-dessous, ou MemTest86 (plusieurs passes).', 'La RAM reservee au materiel (iGPU) reduit la RAM utilisable : normal sur un PC a carte graphique integree.' ) } function Invoke-MehdiHealthLog { Write-Host ' --- Erreurs critiques et erreurs (journal Systeme, 24h) ---' -ForegroundColor Cyan try { $ev = Get-WinEvent -FilterHashtable @{ LogName = 'System'; Level = 1, 2; StartTime = (Get-Date).AddDays(-1) } -MaxEvents 25 -ErrorAction Stop $ev | Select-Object TimeCreated, Id, ProviderName, @{ n = 'Message'; e = { ($_.Message -split "`r?`n")[0] } } | Format-Table -AutoSize -Wrap | Out-Host } catch { Write-Host ' Aucune erreur critique sur les dernieres 24h (ou journal vide).' -ForegroundColor Green } Show-MehdiTips @( 'Kernel-Power (ID 41) = arret brutal du PC : alimentation, surchauffe, RAM, ou prise qui bouge. A surveiller si ca revient.', 'Disk / Ntfs (ID 7, 51, 153) = le disque commence a faiblir : sauvegarde tes donnees et verifie le SMART au plus vite.', 'WHEA-Logger (ID 17, 18, 19) = erreur materielle (CPU, PCIe, RAM) : souvent overclock instable ou composant qui chauffe.', 'BugCheck = ecran bleu : note le code (0x...) pour cibler la cause (souvent un pilote).', 'La meme Application Error qui revient = une appli ou un pilote precis a reparer/reinstaller.' ) } # ---- Menu ---- function Show-DiagnosticsMenu { $items = @( @{ Label = 'Diagnostic audio (micro + sortie)'; Desc = 'Services, peripheriques, confidentialite micro + pistes.'; Action = { Invoke-Step 'Diagnostic audio' { Invoke-MehdiAudioDiag } } } @{ Label = 'Diagnostic webcam'; Desc = 'Cameras, confidentialite + pistes subtiles.'; Action = { Invoke-Step 'Diagnostic webcam' { Invoke-MehdiWebcamDiag } } } @{ Label = 'Diagnostic USB'; Desc = 'Peripheriques USB, etat + pistes (alimentation, veille, cable).'; Action = { Invoke-Step 'Diagnostic USB' { Invoke-MehdiUsbDiag } } } @{ Label = 'Peripheriques en erreur (tous)'; Desc = 'Tout ce qui n est pas OK avec le code de probleme traduit.'; Action = { Invoke-Step 'Peripheriques en erreur' { Invoke-MehdiProblemDevicesDiag } } } @{ Label = 'Verification des pilotes'; Desc = 'Pilotes signes, les plus anciens, fournisseur + pistes.'; Action = { Invoke-Step 'Verification des pilotes' { Invoke-MehdiDriverDiag } } } @{ Label = 'Diagnostic reseau (carte)'; Desc = 'Etat des cartes, debit, MAC + pistes.'; Action = { Invoke-Step 'Diagnostic reseau' { Invoke-MehdiNetDeviceDiag } } } @{ Label = 'Diagnostic affichage / GPU'; Desc = 'Cartes graphiques, pilote, resolution + pistes.'; Action = { Invoke-Step 'Diagnostic affichage' { Invoke-MehdiDisplayDiag } } } @{ Label = 'Batterie & alimentation'; Desc = 'Reveils du PC, ce qui empeche la veille + pistes (portable).'; Action = { Invoke-Step 'Batterie & alimentation' { Invoke-MehdiBatteryDiag } } } @{ Label = 'Rapport batterie (usure)'; Desc = 'Genere et ouvre le rapport d usure de la batterie.'; Action = { Invoke-Step 'Rapport batterie' { Invoke-MehdiBatteryReport } -NoPause } } @{ Label = 'Bluetooth'; Desc = 'Service, peripheriques BT + pistes (appairage, pile, interference USB3).'; Action = { Invoke-Step 'Diagnostic Bluetooth' { Invoke-MehdiBluetoothDiag } } } @{ Label = 'Imprimante'; Desc = 'Spouleur, hors connexion, port + pistes (WSD, file bloquee).'; Action = { Invoke-Step 'Diagnostic imprimante' { Invoke-MehdiPrinterDiag } } } @{ Label = 'Lenteurs & surchauffe'; Desc = 'Top processus CPU/RAM, uptime + pistes (disque 100%, malware, thermique).'; Action = { Invoke-Step 'Lenteurs & surchauffe' { Invoke-MehdiPerfDiag } } } @{ Label = 'Memoire (RAM)'; Desc = 'Barrettes, vitesse, total/libre + pistes (XMP, dual channel).'; Action = { Invoke-Step 'Memoire RAM' { Invoke-MehdiMemoryDiag } } } @{ Label = 'Tester la RAM (au redemarrage)'; Desc = 'Lance l outil de diagnostic memoire Windows (mdsched).'; Action = { Invoke-Step 'Test memoire Windows' { Start-Process 'mdsched.exe' } -Confirm -NoPause } } @{ Label = 'Journal d erreurs (24h)'; Desc = 'Erreurs critiques recentes + pistes (Kernel-Power, disque, WHEA).'; Action = { Invoke-Step 'Journal d erreurs' { Invoke-MehdiHealthLog } } } @{ Label = 'Rapport peripheriques complet'; Desc = 'Synthese rapide de l etat materiel.'; Action = { Invoke-Step 'Rapport peripheriques' { Invoke-MehdiDeviceReport } } } ) Invoke-Menu -Title 'DIAGNOSTIC & PERIPHERIQUES' -Items $items } # ---- modules/drivers.ps1 ---- # ============================================================ # MehdiCore - modules/drivers.ps1 # Module : Pilotes (sauvegarde, mise a jour, inventaire) + pistes # Reutilise Show-MehdiTips et Get-MehdiProblemDevices (diagnostics.ps1) # ============================================================ function Backup-MehdiDrivers { $dest = Join-Path ([Environment]::GetFolderPath('Desktop')) 'MehdiCore-Pilotes' New-Item -ItemType Directory -Path $dest -Force | Out-Null Write-Host ' Export de TOUS les pilotes tiers vers :' -ForegroundColor Cyan Write-Host " $dest" -ForegroundColor White Write-Host '' pnputil /export-driver * $dest Write-Host '' Write-Host ' Termine. Garde ce dossier : tu pourras tout reinstaller apres un format.' -ForegroundColor Green Show-MehdiTips @( 'A faire AVANT un formatage : tu recuperes Wi-Fi, son, chipset sans courir apres les sites constructeurs.', 'Pour reinstaller : Gestionnaire > clic droit sur le peripherique > Mettre a jour le pilote > Parcourir > pointe ce dossier (coche les sous-dossiers).', 'Le GPU, lui, vaut mieux le reprendre a jour chez NVIDIA/AMD/Intel plutot que la version sauvegardee.' ) } function Get-MehdiThirdPartyDriverList { Write-Host ' --- Pilotes tiers installes (paquets oem*.inf) ---' -ForegroundColor Cyan pnputil /enum-drivers Show-MehdiTips @( 'Les paquets oemXX.inf sont les pilotes ajoutes par-dessus Windows (constructeurs).', 'Un meme peripherique peut avoir plusieurs versions empilees : la plus recente est utilisee.', 'Pour retirer un pilote fautif : pnputil /delete-driver oemXX.inf /uninstall (a faire avec prudence).' ) } function Invoke-MehdiScanHardware { Write-Host ' Recherche de modifications materielles...' -ForegroundColor Cyan pnputil /scan-devices Write-Host ' Termine.' -ForegroundColor Green Show-MehdiTips @( 'Utile apres avoir branche un peripherique non detecte, ou apres une reinstallation de pilote.', 'Equivaut au clic droit > Rechercher les modifications materielles du Gestionnaire.' ) } function Open-MehdiOptionalUpdates { Write-Host ' Ouverture des mises a jour facultatives (pilotes via Windows Update)...' -ForegroundColor Cyan Start-Process 'ms-settings:windowsupdate-optionalupdates' Show-MehdiTips @( 'Windows cache souvent les pilotes la : Mises a jour facultatives > Pilotes.', 'Ce ne sont pas toujours les derniers : pour GPU/chipset, le site constructeur reste la reference.' ) } function Invoke-MehdiCheckUpdates { Write-Host ' Lancement d une recherche de mises a jour Windows...' -ForegroundColor Cyan try { Start-Process -FilePath 'UsoClient.exe' -ArgumentList 'StartInteractiveScan' -ErrorAction SilentlyContinue } catch { } Start-Process 'ms-settings:windowsupdate' Show-MehdiTips @( 'Windows Update fournit aussi des pilotes (reseau, chipset) sur un PC fraichement installe.', 'Clique Rechercher des mises a jour : ca declenche la detection des pilotes manquants.' ) } function Get-MehdiMissingDrivers { Write-Host ' --- Peripheriques sans pilote ou en erreur ---' -ForegroundColor Cyan $bad = @(Get-MehdiProblemDevices) if ($bad.Count -eq 0) { Write-Host ' Aucun. Tous les peripheriques ont un pilote fonctionnel.' -ForegroundColor Green } else { $bad | Format-Table Nom, Classe, Etat, Code, Cause -AutoSize -Wrap | Out-Host } Show-MehdiTips @( 'Code 28 = pilote absent : Windows Update, MAJ facultatives, ou pack chipset du constructeur.', 'Un Peripherique PCI inconnu disparait presque toujours apres installation du pack CHIPSET (Intel/AMD).', 'Installe le chipset EN PREMIER : il debloque souvent plusieurs inconnus dun seul coup.' ) } function Get-MehdiGhostDevices { Write-Host ' --- Peripheriques fantomes (deja branches, absents aujourd hui) ---' -ForegroundColor Cyan $ghosts = @(Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.Present -eq $false }) if ($ghosts.Count -eq 0) { Write-Host ' Aucun peripherique fantome notable.' -ForegroundColor Green } else { $ghosts | Select-Object Class, FriendlyName | Sort-Object Class | Format-Table -AutoSize | Out-Host Write-Host (" Total : {0}" -f $ghosts.Count) -ForegroundColor DarkYellow } Show-MehdiTips @( 'Ce sont d anciens peripheriques (cles USB, ecrans, imprimantes) toujours en memoire mais debranches.', 'Pour les retirer : Gestionnaire > Affichage > Afficher les peripheriques caches, puis Desinstaller les grises.', 'Trop de fantomes reseau peuvent bloquer une nouvelle carte avec la meme adresse : les nettoyer aide.' ) } function Open-MehdiDeviceManager { Start-Process 'devmgmt.msc' Write-Host ' Gestionnaire de peripheriques ouvert.' -ForegroundColor Green } function Show-DriversMenu { $items = @( @{ Label = 'Sauvegarder TOUS les pilotes (avant format)'; Desc = 'Exporte les pilotes tiers vers le Bureau pour les reinstaller plus tard.'; Action = { Invoke-Step 'Sauvegarde des pilotes' { Backup-MehdiDrivers } -Confirm } } @{ Label = 'Peripheriques sans pilote / en erreur'; Desc = 'Liste ce qui manque, code traduit + pistes.'; Action = { Invoke-Step 'Peripheriques sans pilote' { Get-MehdiMissingDrivers } } } @{ Label = 'Mises a jour de pilotes (Windows Update facultatif)'; Desc = 'Ouvre la page des pilotes facultatifs.'; Action = { Invoke-Step 'Pilotes facultatifs' { Open-MehdiOptionalUpdates } -NoPause } } @{ Label = 'Rechercher les mises a jour Windows'; Desc = 'Declenche une recherche (fournit aussi des pilotes).'; Action = { Invoke-Step 'Recherche de MAJ' { Invoke-MehdiCheckUpdates } -NoPause } } @{ Label = 'Rechercher de nouveaux peripheriques'; Desc = 'Force la detection du materiel branche (scan).'; Action = { Invoke-Step 'Scan materiel' { Invoke-MehdiScanHardware } } } @{ Label = 'Inventaire des pilotes tiers'; Desc = 'Liste les paquets oem*.inf installes + pistes.'; Action = { Invoke-Step 'Inventaire pilotes' { Get-MehdiThirdPartyDriverList } } } @{ Label = 'Peripheriques fantomes (caches)'; Desc = 'Anciens peripheriques debranches encore en memoire.'; Action = { Invoke-Step 'Peripheriques fantomes' { Get-MehdiGhostDevices } } } @{ Label = 'Ouvrir le Gestionnaire de peripheriques'; Desc = 'Acces direct a devmgmt.msc.'; Action = { Invoke-Step 'Gestionnaire de peripheriques' { Open-MehdiDeviceManager } -NoPause } } ) Invoke-Menu -Title 'PILOTES (DRIVERS)' -Items $items } # ---- modules/security.ps1 ---- # ============================================================ # MehdiCore - modules/security.ps1 # Module : Securite & Windows Defender (avec descriptions) # ============================================================ function Show-SecurityMenu { $items = @( @{ Label = 'Mettre a jour les signatures Defender'; Desc = 'Telecharge les dernieres definitions antivirus avant un scan.'; Action = { Invoke-Step 'Update-MpSignature' { Update-MpSignature } } } @{ Label = 'Analyse rapide Defender'; Desc = 'Scan rapide des emplacements les plus exposes aux menaces.'; Action = { Invoke-Step 'Analyse rapide' { Start-MpScan -ScanType QuickScan } } } @{ Label = 'Analyse complete Defender'; Desc = 'Scan de tout le disque (long mais approfondi).'; Action = { Invoke-Step 'Analyse complete' { Start-MpScan -ScanType FullScan } -Confirm } } @{ Label = 'Etat de Windows Defender'; Desc = 'Verifie si l''antivirus et la protection temps reel sont actifs.'; Action = { Invoke-Step 'Etat de Defender' { Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled, AntivirusSignatureVersion, QuickScanAge, FullScanAge | Format-List | Out-Host } } } @{ Label = 'Historique des menaces Defender'; Desc = 'Liste les menaces deja detectees sur le PC.'; Action = { Invoke-Step 'Historique des menaces' { $th = Get-MpThreat -ErrorAction SilentlyContinue; if ($th) { $th | Select-Object ThreatName, SeverityID | Format-Table -AutoSize | Out-Host } else { Write-Host ' Aucune menace dans l historique.' } } } } @{ Label = 'Desactiver la protection en temps reel'; Desc = 'Coupe temporairement l''antivirus (peut etre bloque par la Protection contre les falsifications).'; Action = { Invoke-Step 'Desactiver protection temps reel' { Set-MpPreference -DisableRealtimeMonitoring $true; Write-Host ' Protection temps reel desactivee (si autorise).' } -Confirm } } @{ Label = 'Reactiver la protection en temps reel'; Desc = 'Remet l''antivirus en protection active.'; Action = { Invoke-Step 'Reactiver protection temps reel' { Set-MpPreference -DisableRealtimeMonitoring $false; Write-Host ' Protection temps reel reactivee.' } } } @{ Label = 'Activer le pare-feu (tous les profils)'; Desc = 'Active le pare-feu Windows sur tous les profils reseau.'; Action = { Invoke-Step 'Activer le pare-feu' { netsh advfirewall set allprofiles state on } } } @{ Label = 'Desactiver le pare-feu (tous les profils)'; Desc = 'Coupe le pare-feu (a n''utiliser que pour un test ponctuel).'; Action = { Invoke-Step 'Desactiver le pare-feu' { netsh advfirewall set allprofiles state off } -Confirm } } @{ Label = 'Etat du chiffrement BitLocker'; Desc = 'Indique si les disques sont chiffres et leur etat de protection.'; Action = { Invoke-Step 'Etat BitLocker' { Get-BitLockerVolume | Select-Object MountPoint, VolumeStatus, ProtectionStatus, EncryptionPercentage | Format-Table -AutoSize | Out-Host } } } @{ Label = 'Creer un compte administrateur local'; Desc = 'Cree un nouvel utilisateur avec droits admin (depannage / acces de secours).'; Action = { Invoke-Step 'Creer un compte admin' { $name = Read-Host ' Nom du compte' if (-not $name) { throw 'Nom vide.' } $pw = Read-Host ' Mot de passe' -AsSecureString New-LocalUser -Name $name -Password $pw -FullName $name -Description 'Cree par MehdiCore' -ErrorAction Stop | Out-Null $adminGroup = (Get-LocalGroup | Where-Object { $_.SID.Value -like '*-544' }).Name Add-LocalGroupMember -Group $adminGroup -Member $name -ErrorAction SilentlyContinue Write-Host " Compte administrateur '$name' cree." } -Confirm } } @{ Label = 'Reinitialiser le mot de passe d un compte'; Desc = 'Change le mot de passe d''un compte local existant.'; Action = { Invoke-Step 'Reinitialiser un mot de passe' { $u = Read-Host ' Nom du compte' if (-not $u) { throw 'Nom vide.' } $p = Read-Host ' Nouveau mot de passe' -AsSecureString Set-LocalUser -Name $u -Password $p -ErrorAction Stop Write-Host " Mot de passe de '$u' reinitialise." } -Confirm } } @{ Label = 'Activer / desactiver le compte invite'; Desc = 'Bascule l''etat du compte Invite integre.'; Action = { Invoke-Step 'Compte invite' { $g = Get-LocalUser | Where-Object { $_.SID.Value -like '*-501' } if ($g.Enabled) { Disable-LocalUser -Name $g.Name; Write-Host ' Compte invite desactive.' } else { Enable-LocalUser -Name $g.Name; Write-Host ' Compte invite active.' } } -Confirm } } ) Invoke-Menu -Title 'SECURITE & DEFENDER' -Items $items } # ---- modules/activation.ps1 ---- # ============================================================ # MehdiCore - modules/activation.ps1 # Module 3 : Activation # S'appuie sur MAS (Microsoft Activation Scripts), l'outil de # reference maintenu par la communaute : https://get.activated.win # # NOTE : Windows Defender / les antivirus signalent frequemment # ce type de script. C'est attendu pour cette categorie d'outil. # ============================================================ function Invoke-MehdiActivation { Write-Host ' Telechargement et lancement de MAS (get.activated.win)...' -ForegroundColor Cyan Write-Host ' MAS prend la main avec son propre menu ; reviens ici en le quittant.' -ForegroundColor DarkGray Write-Host '' Invoke-Expression (Invoke-RestMethod -Uri 'https://get.activated.win') } function Show-ActivationMenu { $items = @( @{ Label = 'Lancer MAS (activation Windows et Office)'; Desc = 'Telecharge et lance MAS pour activer Windows et Office.'; Action = { Invoke-Step 'MAS - get.activated.win' { Invoke-MehdiActivation } -Confirm -NoPause } } ) Invoke-Menu -Title 'ACTIVATION' -Items $items } # ---- modules/apps.ps1 ---- # ============================================================ # MehdiCore - modules/apps.ps1 # Module 4 : Applications (le "MediCat") - lanceur / installeur # Pilote par les donnees : voir src/data/apps.json # Methodes par priorite : portable > winget > command > url # # Portable : # - "url" : URL complete, OU # - "file" : nom de fichier resolu contre ToolsBaseUrl (ton serveur) # - "exe" : executable a lancer dans le .zip (optionnel) # - "ephemeral": true -> telecharge dans TEMP, lance, supprime a la fermeture # false/absent -> mis en cache dans Tools\ (relancable hors-ligne) # ============================================================ function Get-AppsCatalog { if ($script:AppsCatalogJson) { try { return @($script:AppsCatalogJson | ConvertFrom-Json) } catch { Write-Log "Catalogue d'apps illisible : $($_.Exception.Message)" 'ERROR' } } return @() } function Get-MehdiToolsDir { $dir = $script:MehdiCore.ToolsDir if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } return $dir } # Resout l'URL de telechargement : "url" complete, sinon "file" + ToolsBaseUrl. function Resolve-MehdiPortableUrl { param([Parameter(Mandatory = $true)]$App) if ($App.portable.url) { return $App.portable.url } if ($App.portable.file) { $base = ($script:MehdiCore.ToolsBaseUrl).TrimEnd('/') return "$base/$($App.portable.file)" } throw "Aucune 'url' ni 'file' definie pour '$($App.name)'." } # Verifie qu'un .zip est complet (lit le End of Central Directory). function Test-MehdiZipValid { param([string]$Path) if ($Path -notmatch '\.zip$') { return $true } if (-not (Test-Path $Path)) { return $false } try { Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue $zip = [System.IO.Compression.ZipFile]::OpenRead($Path) $zip.Dispose() return $true } catch { return $false } } # Telechargement robuste : BITS (progression + reprise) -> WebClient -> IWR. function Get-MehdiDownload { param([string]$Url, [string]$Dest) try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch { } try { Import-Module BitsTransfer -ErrorAction Stop Start-BitsTransfer -Source $Url -Destination $Dest -Description 'MehdiCore' -ErrorAction Stop return } catch { } try { (New-Object System.Net.WebClient).DownloadFile($Url, $Dest) return } catch { } $prev = $ProgressPreference; $ProgressPreference = 'SilentlyContinue' try { Invoke-WebRequest -Uri $Url -OutFile $Dest -UseBasicParsing } finally { $ProgressPreference = $prev } } # Telecharge puis lance un outil portable (cache ou ephemere). function Invoke-AppPortable { param([Parameter(Mandatory = $true)]$App) $url = Resolve-MehdiPortableUrl $App $ephemeral = [bool]$App.portable.ephemeral $safeName = ($App.name -replace '[\\/:*?"<>|]', '_') if ($ephemeral) { $workDir = Join-Path $env:TEMP ('MehdiCore_' + [guid]::NewGuid().ToString('N').Substring(0, 8)) } else { $workDir = Join-Path (Get-MehdiToolsDir) $safeName } New-Item -ItemType Directory -Path $workDir -Force | Out-Null $file = Join-Path $workDir (Split-Path $url -Leaf) $extract = Join-Path $workDir 'app' # Cache : si le fichier existe mais est tronque/invalide, on repart proprement. if ((Test-Path $file) -and -not $ephemeral) { if (Test-MehdiZipValid $file) { Write-Host " Deja en cache : $file" -ForegroundColor DarkGray } else { Write-Host ' Cache invalide (telechargement precedent interrompu) - on recommence.' -ForegroundColor Yellow Remove-Item $file -Force -ErrorAction SilentlyContinue Remove-Item $extract -Recurse -Force -ErrorAction SilentlyContinue } } if (-not (Test-Path $file)) { Write-Host " Telechargement de $($App.name)..." -ForegroundColor Cyan Get-MehdiDownload -Url $url -Dest $file } # Garde-fou : ne jamais extraire un zip incomplet. if (-not (Test-MehdiZipValid $file)) { Remove-Item $file -Force -ErrorAction SilentlyContinue throw "Telechargement incomplet ou fichier non valide pour '$($App.name)'. Relance pour reessayer." } $exe = $null if ($file -match '\.zip$') { if (-not (Test-Path $extract)) { Write-Host " Extraction..." -ForegroundColor Cyan try { Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue [System.IO.Compression.ZipFile]::ExtractToDirectory($file, $extract) } catch { Expand-Archive -LiteralPath $file -DestinationPath $extract -Force } } if ($App.portable.exe) { $exe = Join-Path $extract $App.portable.exe if (-not (Test-Path $exe)) { $leaf = Split-Path $App.portable.exe -Leaf $found = Get-ChildItem -Path $extract -Recurse -Filter $leaf -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { $exe = $found.FullName } } } else { $found = Get-ChildItem -Path $extract -Recurse -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { $exe = $found.FullName } } } else { $exe = $file } if (-not ($exe -and (Test-Path $exe))) { throw "Executable portable introuvable pour '$($App.name)'." } if ($ephemeral) { Write-Host " Lancement (mode ephemere) : $exe" -ForegroundColor Green Write-Host ' Les fichiers seront supprimes a la fermeture de l''application...' -ForegroundColor DarkGray Start-Process -FilePath $exe -Wait Remove-Item -Path $workDir -Recurse -Force -ErrorAction SilentlyContinue Write-Host ' Traces (fichiers) supprimees.' -ForegroundColor Green } else { Write-Host " Lancement : $exe" -ForegroundColor Green Start-Process -FilePath $exe } } # Prepare Windows pour le streaming WebDAV (admin) : service WebClient, # limite de taille du redirecteur levee, domaine DAV en zone de confiance. function Initialize-MehdiWebDav { $params = 'HKLM:\SYSTEM\CurrentControlSet\Services\WebClient\Parameters' try { Set-ItemProperty -Path $params -Name FileSizeLimitInBytes -Value 0xFFFFFFFF -Type DWord -ErrorAction SilentlyContinue Set-ItemProperty -Path $params -Name FsCtlRequestTimeoutInSec -Value 600 -Type DWord -ErrorAction SilentlyContinue } catch { } try { $svc = Get-Service WebClient -ErrorAction Stop if ($svc.StartType -eq 'Disabled') { Set-Service WebClient -StartupType Manual } if ($svc.Status -ne 'Running') { Start-Service WebClient -ErrorAction SilentlyContinue } else { Restart-Service WebClient -Force -ErrorAction SilentlyContinue } } catch { Write-Host ' (Service WebClient indisponible : le streaming WebDAV peut etre limite.)' -ForegroundColor DarkYellow } $h = $script:MehdiCore.StreamHost if ($h) { $zk = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\$h" try { if (-not (Test-Path $zk)) { New-Item -Path $zk -Force | Out-Null } Set-ItemProperty -Path $zk -Name https -Value 2 -Type DWord -ErrorAction SilentlyContinue } catch { } } } # Verifie que le serveur de streaming repond (methode OPTIONS = test WebDAV). function Test-MehdiStreamServer { $base = $script:MehdiCore.StreamHttp Write-Host " Test de $base ..." -ForegroundColor Cyan try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch { } try { $r = Invoke-WebRequest -Uri $base -Method Options -UseBasicParsing -TimeoutSec 15 Write-Host (" Serveur joignable (HTTP {0}). En-tete DAV : {1}" -f [int]$r.StatusCode, $r.Headers['DAV']) -ForegroundColor Green if (-not $r.Headers['DAV']) { Write-Host ' Attention : pas d en-tete DAV -> WebDAV non actif cote serveur.' -ForegroundColor DarkYellow } } catch { Write-Host " Echec : $($_.Exception.Message)" -ForegroundColor Red } } function Get-MehdiFreeDriveLetter { $used = (Get-PSDrive -PSProvider FileSystem -ErrorAction SilentlyContinue).Name foreach ($l in @('M','N','O','P','R','S','T','U','V','W','X','Y','Z')) { if ($used -notcontains $l) { return $l } } return $null } # Lance une app en streaming depuis le serveur (WebDAV) : lecteur ephemere, # le code est charge a la demande, ejection a la fermeture. function Invoke-AppStream { param([Parameter(Mandatory = $true)]$App) Initialize-MehdiWebDav $rel = ($App.stream.path -replace '/', '\').Trim('\') $exeRel = $App.stream.exe $root = $script:MehdiCore.StreamUnc if ($rel) { $unc = Join-Path $root $rel } else { $unc = $root } $letter = Get-MehdiFreeDriveLetter if (-not $letter) { throw 'Aucune lettre de lecteur libre pour le streaming.' } Write-Host ' Connexion au serveur (WebDAV)...' -ForegroundColor Cyan $null = New-PSDrive -Name $letter -PSProvider FileSystem -Root $unc -Scope Global -ErrorAction Stop try { $base = $letter + ':\' $exe = $null if ($exeRel) { $exe = Join-Path $base $exeRel if (-not (Test-Path $exe)) { $leaf = Split-Path $exeRel -Leaf $found = Get-ChildItem -Path $base -Recurse -Filter $leaf -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { $exe = $found.FullName } } } else { $found = Get-ChildItem -Path $base -Recurse -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { $exe = $found.FullName } } if (-not ($exe -and (Test-Path $exe))) { throw "Executable introuvable sur le serveur pour '$($App.name)'." } Write-Host " Lancement en streaming : $(Split-Path $exe -Leaf)" -ForegroundColor Green Write-Host ' (Code charge a la demande ; rien n est installe sur le disque.)' -ForegroundColor DarkGray Start-Process -FilePath $exe -WorkingDirectory (Split-Path $exe -Parent) -Wait } finally { Remove-PSDrive -Name $letter -Force -ErrorAction SilentlyContinue Write-Host ' Lecteur reseau ejecte.' -ForegroundColor Green } } function Invoke-AppAction { param([Parameter(Mandatory = $true)]$App) Invoke-Step "Action : $($App.name)" { if ($App.stream) { Invoke-AppStream $App } elseif ($App.portable) { Invoke-AppPortable $App } elseif ($App.winget) { winget.exe install --id $App.winget -e --accept-source-agreements --accept-package-agreements } elseif ($App.command) { Invoke-Expression $App.command } elseif ($App.url) { Start-Process $App.url } else { throw "Aucune methode d'installation definie pour '$($App.name)'." } } -Confirm } function Clear-MehdiToolsCache { $dir = $script:MehdiCore.ToolsDir if (Test-Path $dir) { Remove-Item -Path $dir -Recurse -Force -ErrorAction SilentlyContinue Write-Host " Cache des outils portables vide : $dir" -ForegroundColor Green } else { Write-Host ' Aucun cache a vider.' -ForegroundColor DarkGray } } function Show-AppCategory { param( [Parameter(Mandatory = $true)][string]$Name, [Parameter(Mandatory = $true)][array]$Apps ) $items = foreach ($a in $Apps) { $app = $a @{ Label = $app.name; Desc = $app.description; Action = { Invoke-AppAction $app }.GetNewClosure() } } Invoke-Menu -Title "APPS - $Name" -Items @($items) } function Show-AppsMenu { $catalog = Get-AppsCatalog $items = @() if ($catalog -and $catalog.Count -gt 0) { $groups = $catalog | Group-Object -Property category foreach ($g in $groups) { $catName = $g.Name $catApps = @($g.Group) $items += @{ Label = "$catName ($($catApps.Count))"; Action = { Show-AppCategory -Name $catName -Apps $catApps }.GetNewClosure() } } } $items += @{ Label = 'Vider le cache des outils portables'; Desc = 'Supprime les outils telecharges dans le dossier Tools.'; Action = { Invoke-Step 'Vider le cache des outils' { Clear-MehdiToolsCache } -Confirm } } Invoke-Menu -Title 'APPLICATIONS (MEDICAT)' -Items @($items) } # ---- main.ps1 ---- # ============================================================ # MehdiCore - main.ps1 # Point d'entree : prerequis, elevation, menu principal. # (Concatene en dernier au build.) # ============================================================ function Start-MehdiCore { $script:MehdiQuit = $false if (-not (Test-Prerequisites)) { return } if (-not (Assert-Admin)) { return } try { $Host.UI.RawUI.WindowTitle = "$($script:MehdiCore.Name) v$($script:MehdiCore.Version)" } catch { } $items = @( @{ Section = 'Maintenance' } @{ Label = 'Reparation systeme'; Desc = 'SFC, DISM, disque, reseau, Windows Update, services...'; Action = { Show-RepairMenu } } @{ Label = 'Tweaks & confidentialite'; Desc = 'Telemetrie, MAJ, interface, vie privee.'; Action = { Show-TweaksMenu } } @{ Label = 'Performance & nettoyage'; Desc = 'Plans d alimentation, debloat, hibernation, journaux.'; Action = { Show-PerformanceMenu } } @{ Section = 'Diagnostic' } @{ Label = 'Diagnostic & peripheriques'; Desc = 'Audio, micro, USB, batterie, GPU... avec pistes (tips).'; Action = { Show-DiagnosticsMenu } } @{ Label = 'Pilotes (drivers)'; Desc = 'Sauvegarder avant format, MAJ, peripheriques sans pilote.'; Action = { Show-DriversMenu } } @{ Section = 'Systeme' } @{ Label = 'Systeme & informations'; Desc = 'Specs, version, cle, Wi-Fi, disques, programmes.'; Action = { Show-SystemInfoMenu } } @{ Label = 'Securite & Defender'; Desc = 'Antivirus, pare-feu, BitLocker, comptes.'; Action = { Show-SecurityMenu } } @{ Section = 'Outils' } @{ Label = 'Activation'; Desc = 'Activer Windows et Office via MAS.'; Action = { Show-ActivationMenu } } @{ Label = 'Applications (MediCat)'; Desc = 'Lancer des outils portables depuis le serveur.'; Action = { Show-AppsMenu } } ) Invoke-Menu -Title 'ACCUEIL' -Items $items -BackLabel 'Quitter' Clear-Host Write-Host '' Write-Host " Merci d'avoir utilise MehdiCore." -ForegroundColor Cyan Write-Host '' } Start-MehdiCore