# MehdiCore - genere par build.py - NE PAS EDITER # Build 2026-06-27T11:43:53.458064 $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/network.ps1 ---- # ============================================================ # MehdiCore - modules/network.ps1 # Reseau avance : diagnostic, DNS, Wi-Fi, ports. Avec pistes. # ============================================================ function Set-MehdiDns { param([string]$Primary, [string]$Secondary, [string]$LabelDns) $adapters = Get-NetAdapter | Where-Object Status -eq 'Up' if (-not $adapters) { Write-Host ' Aucune carte reseau active.' -ForegroundColor DarkYellow; return } foreach ($a in $adapters) { if ($Primary -eq 'auto') { Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ResetServerAddresses -ErrorAction SilentlyContinue } else { Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses @($Primary, $Secondary) -ErrorAction SilentlyContinue } Write-Host " $($a.Name) -> $LabelDns" } ipconfig /flushdns | Out-Null Write-Host " DNS applique : $LabelDns (cache vide)." -ForegroundColor Green } function Test-MehdiPort { $target = Read-Host ' Hote ou IP (ex: google.com, 192.168.1.1)' if (-not $target) { return } $port = Read-Host ' Port (ex: 443, 80, 3389, 22)' if (-not $port) { return } Write-Host " Test de $target sur le port $port ..." -ForegroundColor Cyan Test-NetConnection -ComputerName $target -Port ([int]$port) -InformationLevel Detailed | Out-Host Show-MehdiTips @( 'Ports utiles : 80/443 = web, 3389 = Bureau a distance, 22 = SSH, 445 = partage Windows.', 'TcpTestSucceeded = True : le port est ouvert et joignable. False : ferme, filtre, ou service eteint.' ) } function Get-MehdiPublicIp { try { $ip = (Invoke-RestMethod -Uri 'https://api.ipify.org?format=json' -TimeoutSec 8).ip Write-Host " IP publique : $ip" -ForegroundColor Green } catch { Write-Host ' Impossible de recuperer l IP publique (pas d Internet ?).' -ForegroundColor DarkYellow } Show-MehdiTips @( 'L IP publique est celle vue par les sites web ; l IP locale (192.168.x) est celle du reseau interne.', 'Si elle change a chaque redemarrage de box, c est une IP dynamique (cas le plus frequent).' ) } function Test-MehdiSpeed { $url = 'https://speed.cloudflare.com/__down?bytes=25000000' # ~25 Mo Write-Host ' Mesure du debit de telechargement (~25 Mo via Cloudflare)...' -ForegroundColor Cyan try { $sw = [System.Diagnostics.Stopwatch]::StartNew() $f = Join-Path $env:TEMP 'mehdicore-speed.bin' (New-Object System.Net.WebClient).DownloadFile($url, $f) $sw.Stop() $size = (Get-Item $f).Length Remove-Item $f -Force -ErrorAction SilentlyContinue $sec = [math]::Max($sw.Elapsed.TotalSeconds, 0.001) $mbps = [math]::Round(($size * 8 / 1MB) / $sec, 1) $mos = [math]::Round(($size / 1MB) / $sec, 1) Write-Host (" Telecharge {0:N0} Mo en {1:N1} s" -f ($size/1MB), $sec) -ForegroundColor Green Write-Host (" Debit estime : {0} Mbps ({1} Mo/s)" -f $mbps, $mos) -ForegroundColor Green } catch { Write-Host ' Mesure impossible (pas d Internet ?).' -ForegroundColor DarkYellow } Show-MehdiTips @( 'Mesure indicative en download seulement : un vrai speedtest teste aussi l upload et le ping.', 'Pour comparer : 100 Mbps environ 12,5 Mo/s. Le Wi-Fi et l heure de la journee font beaucoup varier.' ) } function Show-MehdiWifiProfiles { Write-Host ' --- Profils Wi-Fi enregistres ---' -ForegroundColor Cyan netsh wlan show profiles | Out-Host Show-MehdiTips @( 'Pour voir le mot de passe d un profil : Systeme > Mots de passe Wi-Fi enregistres.', 'Oublier un reseau retire son profil ; pratique si la connexion echoue en boucle.' ) } function Remove-MehdiWifiProfile { $name = Read-Host ' Nom exact du reseau Wi-Fi a oublier' if (-not $name) { return } netsh wlan delete profile name="$name" | Out-Host Write-Host ' Profil supprime (s il existait).' -ForegroundColor Green } function Get-MehdiWifiReport { Write-Host ' Generation du rapport Wi-Fi Windows...' -ForegroundColor Cyan netsh wlan show wlanreport | Out-Null $rep = Join-Path $env:ProgramData 'Microsoft\Windows\WlanReport\wlan-report-latest.html' if (Test-Path $rep) { Start-Process $rep Write-Host " Rapport ouvert : $rep" -ForegroundColor Green } else { Write-Host ' Rapport introuvable.' -ForegroundColor DarkYellow } Show-MehdiTips @( 'Le rapport HTML montre l historique des connexions/deconnexions Wi-Fi des 3 derniers jours.', 'Ideal pour comprendre des coupures Wi-Fi recurrentes (mise en veille de la carte, signal faible...).' ) } function Show-NetworkToolsMenu { $items = @( @{ Section = 'Diagnostic' } @{ Label = 'Configuration IP complete (ipconfig /all)'; Desc = 'Toutes les infos reseau : IP, passerelle, DNS, MAC, DHCP.'; Action = { Invoke-Step 'ipconfig /all' { ipconfig /all | Out-Host } } } @{ Label = 'Cartes reseau et etat'; Desc = 'Liste les cartes reseau, leur vitesse de lien et leur statut.'; Action = { Invoke-Step 'Get-NetAdapter' { Get-NetAdapter | Format-Table Name, InterfaceDescription, Status, LinkSpeed -AutoSize | Out-Host } } } @{ Label = 'Adresse IP publique'; Desc = 'Affiche l IP vue depuis Internet.'; Action = { Invoke-Step 'IP publique' { Get-MehdiPublicIp } } } @{ Label = 'Tester un port (Test-NetConnection)'; Desc = 'Verifie si un port distant est ouvert et joignable.'; Action = { Invoke-Step 'Test de port' { Test-MehdiPort } } } @{ Label = 'Test de debit (download)'; Desc = 'Mesure rapide du debit de telechargement via Cloudflare.'; Action = { Invoke-Step 'Test de debit' { Test-MehdiSpeed } } } @{ Label = 'Ping (hote au choix)'; Desc = 'Teste la latence vers un hote que tu choisis.'; Action = { Invoke-Step 'Ping' { $h = Read-Host ' Hote (Entree = 1.1.1.1)'; if (-not $h) { $h = '1.1.1.1' }; ping $h | Out-Host } } } @{ Label = 'Tracer la route (tracert)'; Desc = 'Affiche le chemin reseau jusqu a une destination.'; Action = { Invoke-Step 'tracert' { $h = Read-Host ' Hote (Entree = 1.1.1.1)'; if (-not $h) { $h = '1.1.1.1' }; tracert $h | Out-Host } } } @{ Label = 'Resolution DNS (nslookup)'; Desc = 'Resout un nom de domaine en adresse(s) IP.'; Action = { Invoke-Step 'nslookup' { $h = Read-Host ' Domaine (ex: github.com)'; if ($h) { nslookup $h | Out-Host } } } } @{ Label = 'Connexions actives (netstat -ano)'; Desc = 'Connexions ouvertes et processus associes.'; Action = { Invoke-Step 'netstat -ano' { netstat -ano | Out-Host } } } @{ Section = 'DNS' } @{ Label = 'DNS Cloudflare (1.1.1.1)'; Desc = 'Applique le DNS Cloudflare sur toutes les cartes actives (rapide, prive).'; Action = { Invoke-Step 'DNS Cloudflare' { Set-MehdiDns '1.1.1.1' '1.0.0.1' 'Cloudflare (1.1.1.1)' } -Confirm } } @{ Label = 'DNS Google (8.8.8.8)'; Desc = 'Applique le DNS Google sur toutes les cartes actives.'; Action = { Invoke-Step 'DNS Google' { Set-MehdiDns '8.8.8.8' '8.8.4.4' 'Google (8.8.8.8)' } -Confirm } } @{ Label = 'DNS Quad9 (9.9.9.9)'; Desc = 'DNS securise qui bloque les domaines malveillants connus.'; Action = { Invoke-Step 'DNS Quad9' { Set-MehdiDns '9.9.9.9' '149.112.112.112' 'Quad9 (9.9.9.9)' } -Confirm } } @{ Label = 'DNS automatique (DHCP)'; Desc = 'Revient au DNS fourni automatiquement par la box.'; Action = { Invoke-Step 'DNS automatique' { Set-MehdiDns 'auto' '' 'Automatique (DHCP)' } -Confirm } } @{ Section = 'Wi-Fi' } @{ Label = 'Profils Wi-Fi enregistres'; Desc = 'Liste les reseaux Wi-Fi memorises sur ce PC.'; Action = { Invoke-Step 'Profils Wi-Fi' { Show-MehdiWifiProfiles } } } @{ Label = 'Etat de la connexion Wi-Fi'; Desc = 'SSID, signal, canal et debit du Wi-Fi actuel.'; Action = { Invoke-Step 'Etat Wi-Fi' { netsh wlan show interfaces | Out-Host } } } @{ Label = 'Rapport Wi-Fi Windows (HTML)'; Desc = 'Historique des connexions Wi-Fi des 3 derniers jours.'; Action = { Invoke-Step 'Rapport Wi-Fi' { Get-MehdiWifiReport } } } @{ Label = 'Oublier un reseau Wi-Fi'; Desc = 'Supprime un profil Wi-Fi memorise.'; Action = { Invoke-Step 'Oublier un Wi-Fi' { Remove-MehdiWifiProfile } -Confirm } } @{ Section = 'Reparation' } @{ Label = 'Vider le cache DNS'; Desc = 'Resout les sites inaccessibles dus a un cache DNS perime.'; Action = { Invoke-Step 'flushdns' { ipconfig /flushdns; Write-Host ' Cache DNS vide.' } } } @{ Label = 'Renouveler l adresse IP (DHCP)'; Desc = 'Libere puis redemande une adresse IP au routeur.'; Action = { Invoke-Step 'Renouvellement IP' { ipconfig /release; ipconfig /renew } } } @{ Label = 'Reset reseau complet'; Desc = 'flushDNS + Winsock + pile IP + proxy. La solution radicale (redemarrage requis).'; Action = { Invoke-Step 'Reset reseau complet' { Reset-MehdiNetwork } -Confirm } } ) Invoke-Menu -Title 'RESEAU AVANCE' -Items $items } # ---- modules/files.ps1 ---- # ============================================================ # MehdiCore - modules/files.ps1 # Fichiers & disques (avance) : hash, doublons, takeown, # debloquer, arbre, vides, espace par dossier. Avec pistes. # ============================================================ function Get-MehdiFileHash { $path = Read-Host ' Chemin du fichier' if (-not (Test-Path $path -PathType Leaf)) { Write-Host ' Fichier introuvable.' -ForegroundColor DarkYellow; return } foreach ($algo in @('MD5', 'SHA1', 'SHA256')) { $h = (Get-FileHash -Path $path -Algorithm $algo).Hash Write-Host (" {0,-7}: {1}" -f $algo, $h) -ForegroundColor Green } Show-MehdiTips @( 'Sert a verifier qu un fichier telecharge n a pas ete altere : compare le SHA256 a celui du site officiel.', 'Tu peux coller un hash sur VirusTotal pour savoir si un fichier est connu comme malveillant.' ) } function Find-MehdiDuplicates { $root = Read-Host ' Dossier a analyser (Entree = Telechargements)' if (-not $root) { $root = Join-Path $env:USERPROFILE 'Downloads' } if (-not (Test-Path $root)) { Write-Host ' Dossier introuvable.' -ForegroundColor DarkYellow; return } Write-Host " Recherche de doublons (par taille puis hash) dans $root ..." -ForegroundColor Cyan $files = Get-ChildItem -Path $root -Recurse -File -Force -ErrorAction SilentlyContinue $bySize = $files | Group-Object Length | Where-Object { $_.Count -gt 1 } $dups = @() foreach ($g in $bySize) { $g.Group | Get-FileHash -Algorithm MD5 -ErrorAction SilentlyContinue | Group-Object Hash | Where-Object { $_.Count -gt 1 } | ForEach-Object { foreach ($f in $_.Group) { $dups += [pscustomobject]@{ Hash = $_.Name.Substring(0,8); Fichier = $f.Path } } } } if ($dups.Count) { $dups | Sort-Object Hash | Select-Object -First 200 | Format-Table -AutoSize | Out-Host; Write-Host (" {0} fichier(s) en double (max 200 affiches)." -f $dups.Count) -ForegroundColor Green } else { Write-Host ' Aucun doublon trouve.' -ForegroundColor Green } Show-MehdiTips @( 'Memes hash = contenu identique, meme si le nom differe : tu peux supprimer toutes les copies sauf une.', 'Lance ca sur Telechargements ou Images : c est la que s accumulent le plus de doublons.' ) } function Unblock-MehdiFile { $path = Read-Host ' Chemin du fichier ou dossier a debloquer' if (-not (Test-Path $path)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } if (Test-Path $path -PathType Container) { Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue | Unblock-File -ErrorAction SilentlyContinue Write-Host ' Tous les fichiers du dossier debloques.' -ForegroundColor Green } else { Unblock-File -Path $path -ErrorAction SilentlyContinue Write-Host ' Fichier debloque.' -ForegroundColor Green } Show-MehdiTips @( 'Windows "bloque" les fichiers venus d Internet (marque de provenance) : ca empeche parfois de les ouvrir.', 'Utile pour un .ps1, .exe ou .dll telecharge que Windows refuse de lancer en pretextant la securite.' ) } function Take-MehdiOwnership { $path = Read-Host ' Chemin du fichier ou dossier' if (-not (Test-Path $path)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } if (Test-Path $path -PathType Container) { cmd /c "takeown /f `"$path`" /r /d O" | Out-Host cmd /c "icacls `"$path`" /grant *S-1-3-4:F /t /c" | Out-Host } else { cmd /c "takeown /f `"$path`"" | Out-Host cmd /c "icacls `"$path`" /grant *S-1-3-4:F" | Out-Host } Write-Host ' Proprietaire et droits accordes a l utilisateur courant.' -ForegroundColor Green Show-MehdiTips @( 'A utiliser quand Windows refuse de modifier/supprimer un fichier (Acces refuse) qui ne t appartient pas.', 'Manipuler des fichiers systeme proteges peut casser Windows : ne le fais que si tu sais ce que tu fais.' ) } function Show-MehdiTree { $root = Read-Host ' Dossier (Entree = dossier courant utilisateur)' if (-not $root) { $root = $env:USERPROFILE } if (-not (Test-Path $root)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } cmd /c "tree `"$root`" /A" | Select-Object -First 300 | Out-Host Show-MehdiTips @('Affiche l arborescence des dossiers (max 300 lignes). Ajoute /F dans cmd pour aussi voir les fichiers.') } function Find-MehdiEmpty { $root = Read-Host ' Dossier a analyser' if (-not (Test-Path $root)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } Write-Host ' --- Dossiers vides ---' -ForegroundColor Cyan Get-ChildItem -Path $root -Recurse -Directory -Force -ErrorAction SilentlyContinue | Where-Object { @(Get-ChildItem $_.FullName -Force -ErrorAction SilentlyContinue).Count -eq 0 } | Select-Object -First 100 FullName | Format-Table -AutoSize | Out-Host Write-Host ' --- Fichiers vides (0 octet) ---' -ForegroundColor Cyan Get-ChildItem -Path $root -Recurse -File -Force -ErrorAction SilentlyContinue | Where-Object { $_.Length -eq 0 } | Select-Object -First 100 FullName | Format-Table -AutoSize | Out-Host Show-MehdiTips @('Pratique pour faire le menage apres une desinstallation ou un transfert de fichiers rate.') } function Get-MehdiFolderSizes { $root = Read-Host ' Dossier parent (Entree = C:\Users)' if (-not $root) { $root = 'C:\Users' } if (-not (Test-Path $root)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } Write-Host " Calcul de la taille des sous-dossiers de $root (peut prendre un moment)..." -ForegroundColor Cyan Get-ChildItem -Path $root -Directory -Force -ErrorAction SilentlyContinue | ForEach-Object { $size = (Get-ChildItem $_.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum [pscustomobject]@{ 'Mo' = [math]::Round(($size) / 1MB, 1); Dossier = $_.FullName } } | Sort-Object Mo -Descending | Select-Object -First 25 | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Repere d un coup d oeil quels dossiers mangent ta place disque.', 'Pour une carte visuelle complete, des outils comme WizTree/TreeSize vont plus loin.' ) } function Rename-MehdiBatch { $root = Read-Host ' Dossier contenant les fichiers' if (-not (Test-Path $root)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } $filter = Read-Host ' Filtre (Entree = *.*)' if (-not $filter) { $filter = '*.*' } $find = Read-Host ' Texte a remplacer dans les noms' if (-not $find) { Write-Host ' Annule.' -ForegroundColor DarkGray; return } $repl = Read-Host ' Remplacer par (vide = supprimer le texte)' $files = Get-ChildItem -Path $root -Filter $filter -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "*$find*" } if (-not $files) { Write-Host ' Aucun fichier ne correspond.' -ForegroundColor DarkYellow; return } Write-Host " $($files.Count) fichier(s) seront renommes :" -ForegroundColor Cyan $files | Select-Object -First 10 | ForEach-Object { Write-Host (" {0} -> {1}" -f $_.Name, ($_.Name -replace [regex]::Escape($find), $repl)) } if (Confirm-Action 'Confirmer le renommage ?') { foreach ($f in $files) { Rename-Item -Path $f.FullName -NewName ($f.Name -replace [regex]::Escape($find), $repl) -ErrorAction SilentlyContinue } Write-Host ' Renommage termine.' -ForegroundColor Green } else { Write-Host ' Annule.' -ForegroundColor DarkGray } } function Export-MehdiInstalledList { $out = Join-Path ([Environment]::GetFolderPath('Desktop')) 'mehdicore-programmes.txt' $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 -Unique | Out-File -FilePath $out -Encoding UTF8 Write-Host " Liste exportee : $out" -ForegroundColor Green Show-MehdiTips @('Garde ce fichier avant un formatage : tu sauras exactement quoi reinstaller.') } function Show-FilesAdvancedMenu { $items = @( @{ Section = 'Verification & integrite' } @{ Label = 'Calculer le hash d un fichier (MD5/SHA)'; Desc = 'Verifie l integrite d un fichier telecharge ou suspect.'; Action = { Invoke-Step 'Hash d un fichier' { Get-MehdiFileHash } } } @{ Label = 'Trouver les fichiers en double'; Desc = 'Detecte les copies identiques (par taille puis hash).'; Action = { Invoke-Step 'Fichiers en double' { Find-MehdiDuplicates } } } @{ Label = 'Debloquer un fichier telecharge'; Desc = 'Retire la marque "provenance Internet" qui bloque un fichier.'; Action = { Invoke-Step 'Debloquer un fichier' { Unblock-MehdiFile } } } @{ Section = 'Acces & droits' } @{ Label = 'Prendre possession (takeown)'; Desc = 'Force l acces a un fichier/dossier "Acces refuse".'; Action = { Invoke-Step 'Prise de possession' { Take-MehdiOwnership } -Confirm } } @{ Section = 'Exploration & menage' } @{ Label = 'Taille des sous-dossiers'; Desc = 'Classe les sous-dossiers par espace occupe (top 25).'; Action = { Invoke-Step 'Taille des dossiers' { Get-MehdiFolderSizes } } } @{ Label = 'Arborescence d un dossier (tree)'; Desc = 'Affiche la structure des sous-dossiers.'; Action = { Invoke-Step 'Arborescence' { Show-MehdiTree } } } @{ Label = 'Trouver fichiers et dossiers vides'; Desc = 'Liste les dossiers vides et les fichiers de 0 octet.'; Action = { Invoke-Step 'Vides' { Find-MehdiEmpty } } } @{ Label = 'Renommer en lot (rechercher/remplacer)'; Desc = 'Remplace un texte dans le nom de plusieurs fichiers d un coup.'; Action = { Invoke-Step 'Renommage en lot' { Rename-MehdiBatch } } } @{ Section = 'Export' } @{ Label = 'Exporter la liste des programmes installes'; Desc = 'Sauvegarde un .txt sur le Bureau (utile avant un format).'; Action = { Invoke-Step 'Export programmes' { Export-MehdiInstalledList } } } ) Invoke-Menu -Title 'FICHIERS & DISQUES (AVANCE)' -Items $items } # ---- modules/sysplus.ps1 ---- # ============================================================ # MehdiCore - modules/sysplus.ps1 # Infos systeme (avance) : materiel, securite plateforme, # GPU/RAM/moniteurs, rapport complet. Avec pistes. # ============================================================ function Get-MehdiHardwareId { $cs = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue $bios= Get-CimInstance Win32_BIOS -ErrorAction SilentlyContinue $bb = Get-CimInstance Win32_BaseBoard -ErrorAction SilentlyContinue Write-Host (" Fabricant : {0}" -f $cs.Manufacturer) Write-Host (" Modele : {0}" -f $cs.Model) Write-Host (" Numero de serie: {0}" -f $bios.SerialNumber) Write-Host (" Carte mere : {0} {1}" -f $bb.Manufacturer, $bb.Product) Write-Host (" BIOS/UEFI : {0} (v{1})" -f $bios.Manufacturer, $bios.SMBIOSBIOSVersion) try { Write-Host (" Date du BIOS : {0:yyyy-MM-dd}" -f ([Management.ManagementDateTimeConverter]::ToDateTime($bios.ReleaseDate))) } catch { } Show-MehdiTips @( 'Le numero de serie sert pour la garantie et le support du fabricant.', 'Une date de BIOS tres ancienne peut justifier une mise a jour (stabilite, compatibilite CPU/RAM).' ) } function Get-MehdiCpuInfo { Get-CimInstance Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, @{ n = 'MaxMHz'; e = { $_.MaxClockSpeed } }, L2CacheSize, L3CacheSize | Format-List | Out-Host Show-MehdiTips @('Coeurs = unites physiques, processeurs logiques = avec l Hyper-Threading/SMT.') } function Get-MehdiRamModules { Write-Host ' --- Barrettes de RAM installees ---' -ForegroundColor Cyan Get-CimInstance Win32_PhysicalMemory -ErrorAction SilentlyContinue | ForEach-Object { [pscustomobject]@{ Emplacement = $_.DeviceLocator 'Go' = [math]::Round($_.Capacity / 1GB) 'MHz' = $_.Speed Fabricant = $_.Manufacturer Reference = $_.PartNumber } } | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Verifie si tous les slots sont occupes et a quelle vitesse : utile avant d ajouter de la RAM.', 'Pour le dual-channel, mieux vaut deux barrettes identiques que des references melangees.' ) } function Get-MehdiGpuInfo { Get-CimInstance Win32_VideoController -ErrorAction SilentlyContinue | ForEach-Object { [pscustomobject]@{ Carte = $_.Name 'VRAM(Go)' = if ($_.AdapterRAM) { [math]::Round($_.AdapterRAM / 1GB, 1) } else { 'n/a' } Resolution = "$($_.CurrentHorizontalResolution)x$($_.CurrentVerticalResolution)" Pilote = $_.DriverVersion 'Pilote du' = try { [Management.ManagementDateTimeConverter]::ToDateTime($_.DriverDate).ToString('yyyy-MM-dd') } catch { 'n/a' } } } | Format-List | Out-Host Show-MehdiTips @('La VRAM signalee par Windows peut etre sous-estimee pour les grosses cartes ; verifie via dxdiag.') } function Get-MehdiMonitors { Get-CimInstance -Namespace root\wmi -ClassName WmiMonitorID -ErrorAction SilentlyContinue | ForEach-Object { $name = ($_.UserFriendlyName | Where-Object { $_ -ne 0 } | ForEach-Object { [char]$_ }) -join '' $serial = ($_.SerialNumberID | Where-Object { $_ -ne 0 } | ForEach-Object { [char]$_ }) -join '' [pscustomobject]@{ Moniteur = $name; Serie = $serial } } | Format-Table -AutoSize | Out-Host Show-MehdiTips @('Identifie precisement chaque ecran (modele + numero de serie), meme sur un setup multi-ecrans.') } function Get-MehdiTpmSecureBoot { Write-Host ' --- TPM (puce de securite) ---' -ForegroundColor Cyan try { $tpm = Get-Tpm -ErrorAction Stop Write-Host (" Present : {0} | Active : {1} | Pret : {2}" -f $tpm.TpmPresent, $tpm.TpmEnabled, $tpm.TpmReady) } catch { Write-Host ' TPM non interrogeable (absent ou non supporte).' -ForegroundColor DarkYellow } Write-Host ' --- Secure Boot ---' -ForegroundColor Cyan try { $sb = Confirm-SecureBootUEFI -ErrorAction Stop if ($sb) { Write-Host ' Secure Boot : ACTIVE' -ForegroundColor Green } else { Write-Host ' Secure Boot : desactive' -ForegroundColor DarkYellow } } catch { Write-Host ' Secure Boot non determinable (BIOS herite/Legacy ou non UEFI).' -ForegroundColor DarkYellow } Show-MehdiTips @( 'TPM 2.0 + Secure Boot sont requis pour Windows 11 et pour BitLocker.', 'Si Secure Boot est desactive, c est dans le BIOS/UEFI qu il faut le reactiver.' ) } function Get-MehdiInstallDate { $os = Get-CimInstance Win32_OperatingSystem Write-Host (" Edition Windows : {0}" -f $os.Caption) Write-Host (" Version/Build : {0} (build {1})" -f $os.Version, $os.BuildNumber) Write-Host (" Architecture : {0}" -f $os.OSArchitecture) try { Write-Host (" Date d installation: {0:yyyy-MM-dd HH:mm}" -f $os.InstallDate) } catch { } try { Write-Host (" Dernier demarrage : {0:yyyy-MM-dd HH:mm}" -f $os.LastBootUpTime) } catch { } Show-MehdiTips @('La date d installation indique l age reel de ton Windows (utile pour decider d un format propre).') } function Export-MehdiSystemReport { $out = Join-Path ([Environment]::GetFolderPath('Desktop')) ("mehdicore-rapport-systeme-{0}.txt" -f (Get-Date -Format 'yyyyMMdd-HHmm')) "==== RAPPORT SYSTEME MEHDICORE ($(Get-Date)) ====" | Out-File $out -Encoding UTF8 "`n--- systeminfo ---" | Out-File $out -Append -Encoding UTF8 systeminfo | Out-File $out -Append -Encoding UTF8 "`n--- Disques ---" | Out-File $out -Append -Encoding UTF8 Get-CimInstance Win32_DiskDrive | Select-Object Model, @{n='Go';e={[math]::Round($_.Size/1GB)}}, InterfaceType | Out-File $out -Append -Encoding UTF8 "`n--- RAM ---" | Out-File $out -Append -Encoding UTF8 Get-CimInstance Win32_PhysicalMemory | Select-Object DeviceLocator, @{n='Go';e={[math]::Round($_.Capacity/1GB)}}, Speed, Manufacturer | Out-File $out -Append -Encoding UTF8 "`n--- GPU ---" | Out-File $out -Append -Encoding UTF8 Get-CimInstance Win32_VideoController | Select-Object Name, DriverVersion | Out-File $out -Append -Encoding UTF8 Write-Host " Rapport complet genere : $out" -ForegroundColor Green Show-MehdiTips @('Pratique a envoyer a un depanneur : tout le materiel et l OS dans un seul fichier.') } function Show-SysPlusMenu { $items = @( @{ Section = 'Materiel' } @{ Label = 'Identite machine (serie, carte mere, BIOS)'; Desc = 'Fabricant, modele, numero de serie, version BIOS/UEFI.'; Action = { Invoke-Step 'Identite machine' { Get-MehdiHardwareId } } } @{ Label = 'Processeur (CPU)'; Desc = 'Modele, coeurs, frequence, cache.'; Action = { Invoke-Step 'CPU' { Get-MehdiCpuInfo } } } @{ Label = 'Memoire (barrettes RAM)'; Desc = 'Slots, capacite, vitesse et reference de chaque barrette.'; Action = { Invoke-Step 'RAM' { Get-MehdiRamModules } } } @{ Label = 'Carte(s) graphique(s)'; Desc = 'GPU, VRAM, resolution, version et date du pilote.'; Action = { Invoke-Step 'GPU' { Get-MehdiGpuInfo } } } @{ Label = 'Moniteurs (ecrans)'; Desc = 'Modele et numero de serie de chaque ecran connecte.'; Action = { Invoke-Step 'Moniteurs' { Get-MehdiMonitors } } } @{ Section = 'Plateforme & securite' } @{ Label = 'TPM & Secure Boot'; Desc = 'Pre-requis Windows 11 / BitLocker : etat de la puce TPM et du Secure Boot.'; Action = { Invoke-Step 'TPM & Secure Boot' { Get-MehdiTpmSecureBoot } } } @{ Label = 'Windows : edition, build, date d install'; Desc = 'Version exacte, architecture, anciennete de l installation.'; Action = { Invoke-Step 'Windows' { Get-MehdiInstallDate } } } @{ Section = 'Rapport' } @{ Label = 'Exporter un rapport systeme complet'; Desc = 'Genere un .txt (materiel + OS) sur le Bureau.'; Action = { Invoke-Step 'Rapport systeme' { Export-MehdiSystemReport } } } ) Invoke-Menu -Title 'INFOS SYSTEME (AVANCE)' -Items $items } # ---- modules/secplus.ps1 ---- # ============================================================ # MehdiCore - modules/secplus.ps1 # Securite (avance) : SmartScreen, UAC, ports en ecoute, # hosts, anti-ransomware, exclusions Defender. Avec pistes. # ============================================================ function Get-MehdiListeningPorts { Write-Host ' --- Ports TCP en ecoute (qui attend des connexions) ---' -ForegroundColor Cyan Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Sort-Object LocalPort -Unique | Select-Object LocalAddress, LocalPort, @{ n = 'Processus'; e = { (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName } }, OwningProcess | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Un port en ecoute = un programme qui accepte des connexions reseau. Repere les processus inconnus.', 'Pour fermer un port suspect : identifie le processus, puis arrete-le ou desinstalle l app correspondante.' ) } function Get-MehdiFirewallProfiles { Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction | Format-Table -AutoSize | Out-Host Show-MehdiTips @('Les 3 profils (Domaine/Prive/Public) ont chacun leurs regles : le pare-feu doit etre actif sur tous.') } function Show-MehdiFirewallRules { Write-Host ' --- Regles de pare-feu ENTRANTES autorisees (50 premieres) ---' -ForegroundColor Cyan Get-NetFirewallRule -Direction Inbound -Action Allow -Enabled True -ErrorAction SilentlyContinue | Select-Object -First 50 DisplayName, Profile | Format-Table -AutoSize | Out-Host Show-MehdiTips @('Une regle entrante autorisee ouvre une porte : surveille celles que tu ne reconnais pas.') } function Set-MehdiSmartScreen { param([int]$Enable) if ($Enable) { Set-MehdiReg 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer' 'SmartScreenEnabled' 'RequireAdmin' 'String' Set-MehdiReg 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System' 'EnableSmartScreen' 1 Write-Host ' SmartScreen active.' -ForegroundColor Green } else { Set-MehdiReg 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer' 'SmartScreenEnabled' 'Off' 'String' Set-MehdiReg 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System' 'EnableSmartScreen' 0 Write-Host ' SmartScreen desactive.' -ForegroundColor DarkYellow } } function Set-MehdiUac { param([int]$Level) # 5 = defaut, 0 = desactive Set-MehdiReg 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' 'EnableLUA' ([int]([bool]$Level)) Set-MehdiReg 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' 'ConsentPromptBehaviorAdmin' $Level if ($Level -gt 0) { Write-Host ' UAC remis a son niveau par defaut (redemarrage conseille).' -ForegroundColor Green } else { Write-Host ' UAC desactive (redemarrage requis). Deconseille au quotidien.' -ForegroundColor DarkYellow } } function Show-MehdiHosts { $h = Join-Path $env:windir 'System32\drivers\etc\hosts' Write-Host " --- $h ---" -ForegroundColor Cyan Get-Content $h -ErrorAction SilentlyContinue | Where-Object { $_ -and ($_ -notmatch '^\s*#') } | Out-Host Write-Host ' (lignes non commentees uniquement)' -ForegroundColor DarkGray Show-MehdiTips @( 'Le fichier hosts force la correspondance nom -> IP. Des malwares y ajoutent des redirections.', 'Des lignes vers des sites connus pointant vers 127.0.0.1 ou une IP etrange = a nettoyer.' ) } function Open-MehdiHosts { $h = Join-Path $env:windir 'System32\drivers\etc\hosts' Start-Process notepad.exe $h Write-Host ' Fichier hosts ouvert dans le Bloc-notes (lance en admin pour pouvoir l enregistrer).' -ForegroundColor Green } function Set-MehdiControlledFolders { param([int]$Enable) try { if ($Enable) { Set-MpPreference -EnableControlledFolderAccess Enabled -ErrorAction Stop; Write-Host ' Acces controle aux dossiers ACTIVE (anti-ransomware).' -ForegroundColor Green } else { Set-MpPreference -EnableControlledFolderAccess Disabled -ErrorAction Stop; Write-Host ' Acces controle aux dossiers desactive.' -ForegroundColor DarkYellow } } catch { Write-Host ' Action impossible (Defender desactive ou geree par une autre solution ?).' -ForegroundColor DarkYellow } Show-MehdiTips @( 'L acces controle aux dossiers empeche les apps non approuvees de modifier tes dossiers (protection ransomware).', 'Effet de bord : certains logiciels legitimes peuvent etre bloques ; il faudra les autoriser manuellement.' ) } function Add-MehdiDefenderExclusion { $path = Read-Host ' Chemin a exclure de Windows Defender' if (-not $path) { return } try { Add-MpPreference -ExclusionPath $path -ErrorAction Stop; Write-Host " Exclusion ajoutee : $path" -ForegroundColor Green } catch { Write-Host ' Impossible d ajouter l exclusion.' -ForegroundColor DarkYellow } Show-MehdiTips @( 'Une exclusion dit a Defender d ignorer un dossier : n exclus que ce en quoi tu as confiance.', 'Utile pour des faux positifs sur des outils legitimes (emulateurs, certains jeux, dev).' ) } function Scan-MehdiDefenderPath { $path = Read-Host ' Dossier ou fichier a analyser' if (-not (Test-Path $path)) { Write-Host ' Introuvable.' -ForegroundColor DarkYellow; return } Write-Host " Analyse Defender de $path ..." -ForegroundColor Cyan try { Start-MpScan -ScanType CustomScan -ScanPath $path -ErrorAction Stop; Write-Host ' Analyse terminee.' -ForegroundColor Green } catch { Write-Host ' Analyse impossible (Defender indisponible ?).' -ForegroundColor DarkYellow } } function Show-SecPlusMenu { $items = @( @{ Section = 'Surface d attaque' } @{ Label = 'Ports en ecoute (+ processus)'; Desc = 'Liste les ports ouverts en ecoute et le programme derriere.'; Action = { Invoke-Step 'Ports en ecoute' { Get-MehdiListeningPorts } } } @{ Label = 'Etat des profils de pare-feu'; Desc = 'Verifie que le pare-feu est actif sur les 3 profils.'; Action = { Invoke-Step 'Profils pare-feu' { Get-MehdiFirewallProfiles } } } @{ Label = 'Regles de pare-feu entrantes'; Desc = 'Liste les autorisations entrantes actives.'; Action = { Invoke-Step 'Regles pare-feu' { Show-MehdiFirewallRules } } } @{ Section = 'Protections systeme' } @{ Label = 'Activer SmartScreen'; Desc = 'Avertit avant d executer des fichiers/sites reputes dangereux.'; Action = { Invoke-Step 'Activer SmartScreen' { Set-MehdiSmartScreen 1 } -Confirm } } @{ Label = 'Desactiver SmartScreen'; Desc = 'Supprime les avertissements SmartScreen (deconseille).'; Action = { Invoke-Step 'Desactiver SmartScreen' { Set-MehdiSmartScreen 0 } -Confirm } } @{ Label = 'UAC : remettre au niveau par defaut'; Desc = 'Reactive le controle de compte utilisateur (recommande).'; Action = { Invoke-Step 'UAC defaut' { Set-MehdiUac 5 } -Confirm } } @{ Label = 'UAC : desactiver'; Desc = 'Coupe les invites UAC (deconseille, redemarrage requis).'; Action = { Invoke-Step 'Desactiver UAC' { Set-MehdiUac 0 } -Confirm } } @{ Label = 'Anti-ransomware : activer'; Desc = 'Active l acces controle aux dossiers de Defender.'; Action = { Invoke-Step 'Anti-ransomware ON' { Set-MehdiControlledFolders 1 } -Confirm } } @{ Label = 'Anti-ransomware : desactiver'; Desc = 'Desactive l acces controle aux dossiers.'; Action = { Invoke-Step 'Anti-ransomware OFF' { Set-MehdiControlledFolders 0 } -Confirm } } @{ Section = 'Defender a la demande' } @{ Label = 'Analyser un dossier/fichier (Defender)'; Desc = 'Scan cible d un chemin precis.'; Action = { Invoke-Step 'Scan Defender cible' { Scan-MehdiDefenderPath } } } @{ Label = 'Ajouter une exclusion Defender'; Desc = 'Exclut un chemin de confiance des analyses.'; Action = { Invoke-Step 'Exclusion Defender' { Add-MehdiDefenderExclusion } -Confirm } } @{ Section = 'Fichier hosts' } @{ Label = 'Afficher le fichier hosts'; Desc = 'Detecte des redirections suspectes ajoutees par un malware.'; Action = { Invoke-Step 'Voir hosts' { Show-MehdiHosts } } } @{ Label = 'Ouvrir le fichier hosts (Bloc-notes)'; Desc = 'Pour editer manuellement les redirections.'; Action = { Invoke-Step 'Editer hosts' { Open-MehdiHosts } -NoPause } } ) Invoke-Menu -Title 'SECURITE (AVANCE)' -Items $items } # ---- modules/power.ps1 ---- # ============================================================ # MehdiCore - modules/power.ps1 # Alimentation, session & redemarrage : arret planifie, # options de recuperation, mode sans echec. Avec pistes. # ============================================================ function Invoke-MehdiScheduledShutdown { param([string]$Mode) # 's' = arret, 'r' = redemarrage $min = Read-Host ' Dans combien de minutes ? (0 = tout de suite)' if ($min -notmatch '^\d+$') { Write-Host ' Valeur invalide.' -ForegroundColor DarkYellow; return } $sec = [int]$min * 60 $verb = if ($Mode -eq 'r') { 'Redemarrage' } else { 'Arret' } shutdown.exe /$Mode /t $sec /f Write-Host " $verb programme dans $min minute(s)." -ForegroundColor Green Show-MehdiTips @('Pour annuler avant l echeance : utilise "Annuler l arret/redemarrage programme".') } function Cancel-MehdiShutdown { shutdown.exe /a 2>$null Write-Host ' Tout arret/redemarrage programme a ete annule (s il y en avait un).' -ForegroundColor Green } function Invoke-MehdiAdvancedBoot { Write-Host ' Redemarrage vers les options de demarrage avancees (WinRE)...' -ForegroundColor Cyan shutdown.exe /r /o /t 3 /f Write-Host ' Le PC va redemarrer sur le menu de recuperation dans 3 s.' -ForegroundColor Green Show-MehdiTips @( 'Depuis WinRE : Depannage > Reparation du demarrage, restauration systeme, invite de commandes...', 'C est le menu a viser quand Windows ne demarre plus correctement.' ) } function Invoke-MehdiUefi { Write-Host ' Redemarrage directement dans le BIOS/UEFI...' -ForegroundColor Cyan shutdown.exe /r /fw /t 3 /f Write-Host ' Le PC va redemarrer dans le firmware (UEFI) dans 3 s.' -ForegroundColor Green Show-MehdiTips @('Ne fonctionne que sur les PC en mode UEFI (pas Legacy/BIOS herite).') } function Set-MehdiSafeBoot { param([string]$Type) # 'minimal', 'network', 'off' if ($Type -eq 'off') { bcdedit /deletevalue '{current}' safeboot 2>$null | Out-Null Write-Host ' Demarrage normal retabli pour le prochain demarrage.' -ForegroundColor Green } else { bcdedit /set '{current}' safeboot $Type | Out-Null Write-Host " Le PC demarrera en MODE SANS ECHEC ($Type) au prochain redemarrage." -ForegroundColor Yellow } Show-MehdiTips @( 'IMPORTANT : tant que ce reglage est actif, Windows redemarre en boucle en mode sans echec.', 'Pense a revenir ici pour choisir "Demarrage normal" une fois ton depannage termine.' ) } function Get-MehdiBootInfo { bcdedit /enum '{current}' | Out-Host Show-MehdiTips @('Affiche la configuration de demarrage actuelle (utile pour diagnostiquer un dual-boot).') } function Show-PowerSessionMenu { $items = @( @{ Section = 'Arret & redemarrage' } @{ Label = 'Redemarrer maintenant'; Desc = 'Redemarre le PC immediatement.'; Action = { Invoke-Step 'Redemarrer' { shutdown.exe /r /t 0 /f } -Confirm -NoPause } } @{ Label = 'Arreter maintenant'; Desc = 'Eteint le PC immediatement.'; Action = { Invoke-Step 'Arreter' { shutdown.exe /s /t 0 /f } -Confirm -NoPause } } @{ Label = 'Redemarrage planifie'; Desc = 'Programme un redemarrage dans X minutes.'; Action = { Invoke-Step 'Redemarrage planifie' { Invoke-MehdiScheduledShutdown 'r' } } } @{ Label = 'Arret planifie'; Desc = 'Programme un arret dans X minutes.'; Action = { Invoke-Step 'Arret planifie' { Invoke-MehdiScheduledShutdown 's' } } } @{ Label = 'Annuler l arret/redemarrage planifie'; Desc = 'Stoppe un arret ou redemarrage programme.'; Action = { Invoke-Step 'Annuler shutdown' { Cancel-MehdiShutdown } } } @{ Section = 'Recuperation & demarrage' } @{ Label = 'Options de demarrage avancees (WinRE)'; Desc = 'Redemarre vers le menu de recuperation Windows.'; Action = { Invoke-Step 'WinRE' { Invoke-MehdiAdvancedBoot } -Confirm -NoPause } } @{ Label = 'Redemarrer dans le BIOS/UEFI'; Desc = 'Va directement dans le firmware au redemarrage (UEFI).'; Action = { Invoke-Step 'UEFI' { Invoke-MehdiUefi } -Confirm -NoPause } } @{ Label = 'Demarrer en mode sans echec'; Desc = 'Prochain demarrage en mode sans echec (minimal).'; Action = { Invoke-Step 'Mode sans echec' { Set-MehdiSafeBoot 'minimal' } -Confirm } } @{ Label = 'Mode sans echec avec reseau'; Desc = 'Prochain demarrage en mode sans echec + reseau.'; Action = { Invoke-Step 'Mode sans echec reseau' { Set-MehdiSafeBoot 'network' } -Confirm } } @{ Label = 'Revenir au demarrage normal'; Desc = 'Annule le mode sans echec pour le prochain demarrage.'; Action = { Invoke-Step 'Demarrage normal' { Set-MehdiSafeBoot 'off' } } } @{ Label = 'Configuration de demarrage (bcdedit)'; Desc = 'Affiche les parametres de boot actuels.'; Action = { Invoke-Step 'Boot info' { Get-MehdiBootInfo } } } @{ Section = 'Session' } @{ Label = 'Verrouiller la session'; Desc = 'Verrouille le PC immediatement (comme Win+L).'; Action = { Invoke-Step 'Verrouiller' { rundll32.exe user32.dll,LockWorkStation } -NoPause } } @{ Label = 'Fermer la session (deconnexion)'; Desc = 'Deconnecte l utilisateur courant.'; Action = { Invoke-Step 'Deconnexion' { shutdown.exe /l } -Confirm -NoPause } } @{ Label = 'Mettre en veille'; Desc = 'Bascule le PC en veille immediatement.'; Action = { Invoke-Step 'Veille' { rundll32.exe powrprof.dll,SetSuspendState 0,1,0 } -NoPause } } ) Invoke-Menu -Title 'ALIMENTATION, SESSION & REDEMARRAGE' -Items $items } # ---- modules/outils.ps1 ---- # ============================================================ # MehdiCore - modules/outils.ps1 # Boite a outils : recherche fichiers, lanceurs Windows, # Windows Update avance (wushowhide), astuces. Avec pistes. # ============================================================ # ---- Recherche & fichiers ---- function Search-MehdiFileByName { $pat = Read-Host ' Nom ou motif (ex: *.log, rapport*.pdf)' if (-not $pat) { Write-Host ' Annule.' -ForegroundColor DarkGray; return } $root = Read-Host ' Dossier de depart (Entree = C:\)' if (-not $root) { $root = 'C:\' } Write-Host " Recherche de '$pat' dans $root ..." -ForegroundColor Cyan $res = @(Get-ChildItem -Path $root -Recurse -Filter $pat -Force -ErrorAction SilentlyContinue | Select-Object -First 200 FullName, @{ n = 'Ko'; e = { [math]::Round($_.Length / 1KB) } }, LastWriteTime) if ($res.Count) { $res | Format-Table -AutoSize | Out-Host; Write-Host (" {0} resultat(s) (max 200)." -f $res.Count) -ForegroundColor Green } else { Write-Host ' Aucun resultat.' -ForegroundColor DarkYellow } Show-MehdiTips @( 'Jokers acceptes : *.exe, recap_2024*.xlsx, photo??.jpg.', 'Le -Force inclut les fichiers caches et systeme (souvent la ou se planque ce qu on cherche).', 'Pars d un sous-dossier precis plutot que de C:\ pour aller beaucoup plus vite.' ) } function Search-MehdiExe { $name = Read-Host ' Nom du programme (ex: notepad, python, ffmpeg)' if (-not $name) { return } Write-Host " where $name :" -ForegroundColor Cyan where.exe $name Show-MehdiTips @( 'where.exe cherche dans le PATH : si rien ne sort, le programme n est pas dans le PATH.', 'Pour fouiller un disque entier : where /R C:\ monfichier.txt (plus lent mais exhaustif).' ) } function Search-MehdiBigFiles { $root = Read-Host ' Dossier a analyser (Entree = C:\Users)' if (-not $root) { $root = 'C:\Users' } Write-Host " Calcul des plus gros fichiers dans $root ..." -ForegroundColor Cyan Get-ChildItem -Path $root -Recurse -File -Force -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object -First 25 @{ n = 'Mo'; e = { [math]::Round($_.Length / 1MB, 1) } }, FullName | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Les nids a place : Telechargements, AppData\Local\Temp, Windows\Temp, fichiers .iso/.vmdk oublies.', 'Combine avec le Nettoyage de disque (cleanmgr) pour liberer la place reperee.' ) } function Search-MehdiRecentFiles { $root = Read-Host ' Dossier (Entree = C:\Users)' if (-not $root) { $root = 'C:\Users' } $days = Read-Host ' Modifies depuis combien de jours (Entree = 2)' if (-not $days) { $days = 2 } $since = (Get-Date).AddDays(-[int]$days) Get-ChildItem -Path $root -Recurse -File -Force -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -ge $since } | Sort-Object LastWriteTime -Descending | Select-Object -First 100 LastWriteTime, FullName | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Parfait pour retrouver un fichier recent dont on a oublie le nom.', 'Sert aussi a voir ce qu un programme (ou un malware) vient de creer/modifier.' ) } function Search-MehdiText { $root = Read-Host ' Dossier' if (-not $root) { Write-Host ' Annule.' -ForegroundColor DarkGray; return } $pat = Read-Host ' Texte a trouver' if (-not $pat) { return } $filter = Read-Host ' Type de fichiers (Entree = *.txt)' if (-not $filter) { $filter = '*.txt' } Get-ChildItem -Path $root -Recurse -Filter $filter -File -ErrorAction SilentlyContinue | Select-String -Pattern $pat -SimpleMatch -ErrorAction SilentlyContinue | Select-Object -First 100 Path, LineNumber, Line | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Cherche dans le CONTENU des fichiers (logs, .ini, .txt, .csv, .xml...).', 'Choisis un type precis (*.log) pour eviter de scanner des gros binaires inutilement.' ) } function Clear-MehdiRecycleBin { Clear-RecycleBin -Force -ErrorAction SilentlyContinue Write-Host ' Corbeille videe.' -ForegroundColor Green } function Show-SearchMenu { $items = @( @{ Label = 'Rechercher un fichier par nom'; Desc = 'Equivaut a where /R : cherche un nom/motif dans toute une arborescence.'; Action = { Invoke-Step 'Recherche par nom' { Search-MehdiFileByName } } } @{ Label = 'Localiser un programme (where)'; Desc = 'Trouve ou est un executable connu du systeme (PATH).'; Action = { Invoke-Step 'Localiser un programme' { Search-MehdiExe } } } @{ Label = 'Trouver les plus gros fichiers'; Desc = 'Top 25 des fichiers les plus volumineux dun dossier.'; Action = { Invoke-Step 'Plus gros fichiers' { Search-MehdiBigFiles } } } @{ Label = 'Fichiers modifies recemment'; Desc = 'Liste les fichiers changes depuis X jours.'; Action = { Invoke-Step 'Fichiers recents' { Search-MehdiRecentFiles } } } @{ Label = 'Rechercher du texte dans des fichiers'; Desc = 'Cherche une chaine dans le contenu (logs, .txt, .csv...).'; Action = { Invoke-Step 'Recherche de texte' { Search-MehdiText } } } @{ Label = 'Vider la corbeille'; Desc = 'Vide definitivement la corbeille de tous les lecteurs.'; Action = { Invoke-Step 'Vider la corbeille' { Clear-MehdiRecycleBin } -Confirm } } ) Invoke-Menu -Title 'RECHERCHE & FICHIERS' -Items $items } # ---- Lanceurs rapides Windows ---- function Show-LaunchersMenu { $tools = @( @('Gestionnaire des taches', 'taskmgr.exe', ''), @('Configuration systeme (msconfig)', 'msconfig.exe', ''), @('Observateur d evenements', 'eventvwr.msc', ''), @('Moniteur de fiabilite', 'perfmon.exe', '/rel'), @('Moniteur de ressources', 'resmon.exe', ''), @('Analyseur de performances', 'perfmon.exe', ''), @('Editeur du Registre', 'regedit.exe', ''), @('Informations systeme (msinfo32)', 'msinfo32.exe', ''), @('Diagnostic DirectX (dxdiag)', 'dxdiag.exe', ''), @('Gestion des disques', 'diskmgmt.msc', ''), @('Gestion de l ordinateur', 'compmgmt.msc', ''), @('Gestionnaire de peripheriques', 'devmgmt.msc', ''), @('Services', 'services.msc', ''), @('Programmes et fonctionnalites', 'appwiz.cpl', ''), @('Connexions reseau', 'ncpa.cpl', ''), @('Proprietes systeme', 'sysdm.cpl', ''), @('Options d alimentation', 'powercfg.cpl', ''), @('Comptes utilisateurs (netplwiz)', 'netplwiz.exe', ''), @('Strategie de groupe locale (Pro)', 'gpedit.msc', ''), @('Strategie de securite locale (Pro)', 'secpol.msc', ''), @('Nettoyage de disque', 'cleanmgr.exe', ''), @('Panneau de configuration', 'control.exe', ''), @('Parametres Windows', 'ms-settings:', ''), @('Fonctionnalites facultatives de Windows', 'optionalfeatures.exe', ''), @('Centre reseau et partage', 'control.exe', '/name Microsoft.NetworkAndSharingCenter'), @('Restauration du systeme', 'rstrui.exe', ''), @('Table des caracteres', 'charmap.exe', ''), @('Clavier visuel', 'osk.exe', '') ) $items = foreach ($t in $tools) { $lbl = $t[0]; $exe = $t[1]; $arg = $t[2] @{ Label = $lbl; Action = { Invoke-Step $lbl { if ($arg) { Start-Process -FilePath $exe -ArgumentList $arg } else { Start-Process $exe } Write-Host " Ouvert : $exe $arg" -ForegroundColor Green } -NoPause }.GetNewClosure() } } Invoke-Menu -Title 'LANCEURS RAPIDES' -Items @($items) } # ---- Windows Update avance ---- function Invoke-MehdiWushowhide { $url = 'https://download.microsoft.com/download/f/2/2/f22d5fdb-59cd-4275-8c95-1be17bf70b21/wushowhide.diagcab' $f = Join-Path $env:TEMP 'wushowhide.diagcab' Write-Host ' Telechargement de l outil Microsoft "Afficher ou masquer les mises a jour"...' -ForegroundColor Cyan try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch { } try { (New-Object System.Net.WebClient).DownloadFile($url, $f) } catch { Invoke-WebRequest -Uri $url -OutFile $f -UseBasicParsing } if (Test-Path $f) { Start-Process $f; Write-Host ' Outil lance.' -ForegroundColor Green } else { Write-Host ' Echec du telechargement.' -ForegroundColor Red } Show-MehdiTips @( 'Sert a MASQUER une mise a jour ou un PILOTE qui pose probleme, pour que Windows arrete de le reproposer en boucle.', 'Cas typique : une MAJ de pilote casse le son/Wi-Fi/GPU. Tu remets l ancien pilote PUIS tu masques la MAJ ici.', 'Pour annuler : relance l outil et choisis "Afficher les mises a jour masquees".' ) } function Get-MehdiUpdateHistory { Write-Host ' --- Correctifs installes (recents en tete) ---' -ForegroundColor Cyan Get-HotFix -ErrorAction SilentlyContinue | Sort-Object InstalledOn -Descending | Select-Object -First 40 HotFixID, Description, InstalledOn | Format-Table -AutoSize | Out-Host Show-MehdiTips @( 'Si les soucis ont commence apres un correctif precis, tu peux le retirer : wusa /uninstall /kb:XXXXXXX.', 'Get-HotFix ne montre pas TOUT (surtout les MAJ de fonctionnalite) : complete avec Parametres > Historique des mises a jour.' ) } function Invoke-MehdiCheckWindowsUpdate { try { Start-Process -FilePath 'UsoClient.exe' -ArgumentList 'StartInteractiveScan' -ErrorAction SilentlyContinue } catch { } Start-Process 'ms-settings:windowsupdate' Write-Host ' Recherche de mises a jour lancee.' -ForegroundColor Green } function Show-WUToolsMenu { $items = @( @{ Label = 'Masquer une MAJ / un pilote (wushowhide)'; Desc = 'Outil Microsoft pour bloquer une mise a jour ou un pilote fautif.'; Action = { Invoke-Step 'wushowhide' { Invoke-MehdiWushowhide } -NoPause } } @{ Label = 'Historique des correctifs installes'; Desc = 'Liste les KB installes avec leur date + pistes.'; Action = { Invoke-Step 'Historique des MAJ' { Get-MehdiUpdateHistory } } } @{ Label = 'Rechercher les mises a jour'; Desc = 'Force une recherche Windows Update.'; Action = { Invoke-Step 'Recherche de MAJ' { Invoke-MehdiCheckWindowsUpdate } -NoPause } } @{ Label = 'Reinitialiser Windows Update'; Desc = 'Repare un Windows Update bloque (services + caches).'; Action = { Invoke-Step 'Reset Windows Update' { Reset-MehdiWindowsUpdate } -Confirm } } ) Invoke-Menu -Title 'WINDOWS UPDATE AVANCE' -Items $items } # ---- Astuces & raccourcis ---- function Enable-MehdiGodMode { $p = Join-Path ([Environment]::GetFolderPath('Desktop')) 'Mode-Dieu.{ED7BA470-8E54-465E-825C-99712043E01C}' if (-not (Test-Path $p)) { New-Item -ItemType Directory -Path $p | Out-Null } Write-Host ' "Mode Dieu" cree sur le Bureau : toutes les options du Panneau de configuration en une liste.' -ForegroundColor Green } function Clear-MehdiClipboard { try { Set-Clipboard -Value ' ' -ErrorAction Stop } catch { cmd /c "echo off | clip" } Write-Host ' Presse-papiers vide.' -ForegroundColor Green } function Show-MiscMenu { $items = @( @{ Label = 'Creer le "Mode Dieu" sur le Bureau'; Desc = 'Dossier special listant tous les reglages Windows.'; Action = { Invoke-Step 'Mode Dieu' { Enable-MehdiGodMode } -NoPause } } @{ Label = 'Redemarrer l explorateur Windows'; Desc = 'Relance explorer.exe (barre des taches/figee).'; Action = { Invoke-Step 'Redemarrer l explorateur' { Restart-MehdiExplorer } -NoPause } } @{ Label = 'Vider le presse-papiers'; Desc = 'Efface ce qui est en memoire de copie.'; Action = { Invoke-Step 'Vider le presse-papiers' { Clear-MehdiClipboard } -NoPause } } @{ Label = 'Vider le cache du Microsoft Store'; Desc = 'Repare le Store (wsreset) quand il bug.'; Action = { Invoke-Step 'Reset cache Store' { Start-Process 'wsreset.exe' } -NoPause } } @{ Label = 'Verrouiller la session'; Desc = 'Verrouille immediatement le PC (comme Win+L).'; Action = { Invoke-Step 'Verrouiller' { rundll32.exe user32.dll,LockWorkStation } -NoPause } } ) Invoke-Menu -Title 'ASTUCES & RACCOURCIS' -Items $items } # ---- Avance / risque (chaque action confirmee, risque indique) ---- function Reset-MehdiFirewall { netsh advfirewall reset Write-Host ' Pare-feu Windows reinitialise aux valeurs par defaut.' -ForegroundColor Yellow } function Remove-MehdiRestorePoints { vssadmin delete shadows /all /quiet Write-Host ' Tous les points de restauration ont ete supprimes.' -ForegroundColor Yellow } function Clear-MehdiEventLogs { Get-WinEvent -ListLog * -ErrorAction SilentlyContinue | Where-Object { $_.RecordCount -gt 0 } | ForEach-Object { try { wevtutil cl "$($_.LogName)" } catch { } } Write-Host ' Journaux d evenements vides.' -ForegroundColor Green } function Enable-MehdiAdminAccount { net user administrator /active:yes Write-Host ' Compte Administrateur integre ACTIVE (pense a lui mettre un mot de passe).' -ForegroundColor Yellow } function Disable-MehdiUAC { Set-MehdiReg 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' 'EnableLUA' 0 'DWord' Write-Host ' Controle de compte (UAC) desactive - REDEMARRAGE requis.' -ForegroundColor Yellow } function Reset-MehdiComponentStoreBase { DISM.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase Write-Host ' WinSxS nettoye en profondeur.' -ForegroundColor Green } function Remove-MehdiTakeownDelete { $target = Read-Host ' Chemin complet a forcer (verifie bien avant de valider)' if (-not $target) { Write-Host ' Annule.' -ForegroundColor DarkGray; return } if (-not (Test-Path $target)) { Write-Host ' Chemin introuvable.' -ForegroundColor Red; return } takeown /F "$target" /R /A /D O 2>$null icacls "$target" /grant administrators:F /T 2>$null Remove-Item -LiteralPath $target -Recurse -Force -ErrorAction SilentlyContinue if (Test-Path $target) { Write-Host ' Echec partiel (element peut-etre en cours d utilisation).' -ForegroundColor DarkYellow } else { Write-Host ' Supprime.' -ForegroundColor Green } } function Clear-MehdiIconCache { $l = $env:LOCALAPPDATA Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue Remove-Item "$l\IconCache.db" -Force -ErrorAction SilentlyContinue Remove-Item "$l\Microsoft\Windows\Explorer\iconcache*" -Force -ErrorAction SilentlyContinue Remove-Item "$l\Microsoft\Windows\Explorer\thumbcache*" -Force -ErrorAction SilentlyContinue Start-Process explorer.exe Write-Host ' Cache d icones et de vignettes vide.' -ForegroundColor Green } function Invoke-MehdiFactoryReset { Write-Host ' Ouverture de la reinitialisation de Windows...' -ForegroundColor Yellow Start-Process 'systemreset.exe' } function Disable-MehdiHibernation { powercfg /h off Write-Host ' Hibernation desactivee (hiberfil.sys supprime, espace libere).' -ForegroundColor Green } function Enable-MehdiF8Boot { bcdedit /set "{default}" bootmenupolicy legacy | Out-Null Write-Host ' Menu de demarrage avance (F8) reactive.' -ForegroundColor Green } function Show-AdvancedMenu { $items = @( @{ Label = 'Reinitialiser ce PC (Windows)'; Desc = 'RISQUE ELEVE : reinstalle Windows (choix garder ou supprimer les fichiers).'; Action = { Invoke-Step 'Reinitialiser Windows' { Invoke-MehdiFactoryReset } -Confirm -NoPause } } @{ Label = 'Reinitialiser le pare-feu Windows'; Desc = 'RISQUE : supprime toutes les regles de pare-feu personnalisees.'; Action = { Invoke-Step 'Reset pare-feu' { Reset-MehdiFirewall } -Confirm } } @{ Label = 'Supprimer tous les points de restauration'; Desc = 'RISQUE : plus de retour arriere possible via la restauration systeme.'; Action = { Invoke-Step 'Supprimer restaurations' { Remove-MehdiRestorePoints } -Confirm } } @{ Label = 'Vider tous les journaux d evenements'; Desc = 'RISQUE : perte de l historique de diagnostic (utile pour enqueter).'; Action = { Invoke-Step 'Vider journaux' { Clear-MehdiEventLogs } -Confirm } } @{ Label = 'Activer le compte Administrateur integre'; Desc = 'RISQUE securite : compte admin actif, sans mot de passe par defaut.'; Action = { Invoke-Step 'Activer Administrateur' { Enable-MehdiAdminAccount } -Confirm } } @{ Label = 'Desactiver le controle de compte (UAC)'; Desc = 'RISQUE securite eleve : plus de demande d elevation. Redemarrage requis.'; Action = { Invoke-Step 'Desactiver UAC' { Disable-MehdiUAC } -Confirm } } @{ Label = 'Nettoyer WinSxS en profondeur (ResetBase)'; Desc = 'RISQUE : impossible de desinstaller les MAJ deja installees apres coup.'; Action = { Invoke-Step 'WinSxS ResetBase' { Reset-MehdiComponentStoreBase } -Confirm } } @{ Label = 'Forcer la suppression d un element verrouille'; Desc = 'RISQUE : prend la propriete et supprime. Un mauvais chemin peut casser le systeme.'; Action = { Invoke-Step 'Suppression forcee' { Remove-MehdiTakeownDelete } -Confirm } } @{ Label = 'Vider le cache d icones et de vignettes'; Desc = 'Faible risque : relance l explorateur (repare les icones cassees).'; Action = { Invoke-Step 'Cache icones' { Clear-MehdiIconCache } -Confirm -NoPause } } @{ Label = 'Desactiver l hibernation'; Desc = 'Faible risque : libere de l espace, mais desactive la veille prolongee.'; Action = { Invoke-Step 'Desactiver hibernation' { Disable-MehdiHibernation } -Confirm } } @{ Label = 'Reactiver le menu de demarrage F8'; Desc = 'Faible risque : remet le menu de demarrage avance classique.'; Action = { Invoke-Step 'Menu F8' { Enable-MehdiF8Boot } -Confirm } } ) Invoke-Menu -Title 'AVANCE / RISQUE' -Items $items } # ---- Menu principal de la boite a outils ---- function Show-ToolboxMenu { $items = @( @{ Section = 'Recherche' } @{ Label = 'Recherche & fichiers'; Desc = 'Fichier par nom, texte, gros fichiers, recents, where /R...'; Action = { Show-SearchMenu } } @{ Section = 'Acces rapide' } @{ Label = 'Lanceurs rapides Windows'; Desc = 'Ouvrir services, regedit, msconfig, devmgmt, dxdiag...'; Action = { Show-LaunchersMenu } } @{ Section = 'Mises a jour' } @{ Label = 'Windows Update avance'; Desc = 'Masquer une MAJ/pilote (wushowhide), historique, recherche.'; Action = { Show-WUToolsMenu } } @{ Section = 'Divers' } @{ Label = 'Astuces & raccourcis'; Desc = 'Mode Dieu, explorateur, presse-papiers, Store, verrou...'; Action = { Show-MiscMenu } } @{ Section = 'Avance' } @{ Label = 'Avance / risque (avec confirmation)'; Desc = 'Reset PC, pare-feu, UAC, suppression forcee... chaque risque est indique.'; Action = { Show-AdvancedMenu } } ) Invoke-Menu -Title 'BOITE A OUTILS' -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 } } @{ Label = 'Reseau avance'; Desc = 'IP /all, test de port, DNS, profils Wi-Fi, rapport, IP publique.'; Action = { Show-NetworkToolsMenu } } @{ Section = 'Systeme' } @{ Label = 'Systeme & informations'; Desc = 'Specs, version, cle, Wi-Fi, disques, programmes.'; Action = { Show-SystemInfoMenu } } @{ Label = 'Infos systeme (avance)'; Desc = 'Serie, carte mere, TPM, Secure Boot, GPU, RAM, moniteurs, rapport.'; Action = { Show-SysPlusMenu } } @{ Label = 'Securite & Defender'; Desc = 'Antivirus, pare-feu, BitLocker, comptes.'; Action = { Show-SecurityMenu } } @{ Label = 'Securite (avance)'; Desc = 'SmartScreen, UAC, ports en ecoute, hash, hosts, anti-ransomware.'; Action = { Show-SecPlusMenu } } @{ Section = 'Fichiers & alimentation' } @{ Label = 'Fichiers & disques (avance)'; Desc = 'Hash, doublons, takeown, debloquer, arbre, vides, espace par dossier.'; Action = { Show-FilesAdvancedMenu } } @{ Label = 'Alimentation, session & redemarrage'; Desc = 'Arret/redemarrage planifie, options de recup, mode sans echec, UEFI.'; Action = { Show-PowerSessionMenu } } @{ Section = 'Outils' } @{ Label = 'Boite a outils'; Desc = 'wushowhide, where /R, lanceurs Windows, Mode Dieu, astuces.'; Action = { Show-ToolboxMenu } } @{ 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