<# TechAssist Pro - Remote storage diagnostic Read-only script. It only reads device enumeration data and writes a report to the Desktop. It never writes to, formats, repairs or modifies any drive. #> param( # 'Ask' prompts the user; 'Yes'/'No' allow unattended runs. [ValidateSet('Ask', 'Yes', 'No')] [string]$WithMedia = 'Ask' ) $ErrorActionPreference = 'SilentlyContinue' $ProgressPreference = 'SilentlyContinue' Write-Host '' Write-Host ' DIAGNOSTIC TECHASSIST PRO' -ForegroundColor Cyan Write-Host '' Write-Host ' Ce diagnostic se fait en DEUX passages :' Write-Host ' Passage 1 : adaptateur branche, SANS le support a analyser dedans.' Write-Host ' Passage 2 : adaptateur branche, AVEC le support a analyser dedans.' Write-Host '' Write-Host ' Comparer les deux permet de savoir si la panne vient du support' Write-Host ' ou simplement de l adaptateur, du cable ou du port USB.' Write-Host '' if ($WithMedia -eq 'Ask') { $answer = Read-Host ' Le support a analyser est-il actuellement dans l adaptateur ? (O/N)' $isPass2 = $answer -match '^\s*[oOyY]' } else { $isPass2 = $WithMedia -eq 'Yes' } $passLabel = if ($isPass2) { 'AVEC le support' } else { 'SANS le support' } $fileName = if ($isPass2) { 'diagnostic-2-avec-support.txt' } else { 'diagnostic-1-sans-support.txt' } $reportPath = Join-Path ([Environment]::GetFolderPath('Desktop')) $fileName $lines = New-Object System.Collections.Generic.List[string] function Add-Line { param([string]$Text = '') $lines.Add($Text) } function Add-Section { param([string]$Title) Add-Line '' Add-Line '================================================================' Add-Line " $Title" Add-Line '================================================================' } function Add-Result { param($Data, [string]$EmptyMessage = '>>> AUCUN RESULTAT <<<') if ($null -eq $Data) { Add-Line $EmptyMessage; return } $text = $Data | Out-String -Width 220 if ([string]::IsNullOrWhiteSpace($text)) { Add-Line $EmptyMessage } else { Add-Line $text.TrimEnd() } } # ---------------------------------------------------------------- header ---- Add-Line 'DIAGNOSTIC DE STOCKAGE - TechAssist Pro' Add-Line 'Script en lecture seule. Aucune donnee n est modifiee sur vos disques.' Add-Line ("Genere le : " + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')) Add-Line ("PASSAGE : " + $passLabel) # ---------------------------------------------------------------- system ---- Add-Section '1. MACHINE' try { $os = Get-CimInstance Win32_OperatingSystem $cs = Get-CimInstance Win32_ComputerSystem Add-Line ("Systeme : " + $os.Caption + " (build " + $os.BuildNumber + ")") Add-Line ("Machine : " + $cs.Manufacturer + " " + $cs.Model) Add-Line ("PowerShell : " + $PSVersionTable.PSVersion.ToString()) } catch { Add-Line 'Lecture des informations systeme impossible.' } $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) Add-Line ("Mode admin : " + $(if ($isAdmin) { 'OUI' } else { 'NON (certaines sections seront vides)' })) # ------------------------------------------------------- physical devices ---- Add-Section '2. DISQUES PHYSIQUES VUS PAR WINDOWS (Get-Disk)' Add-Line 'Si le SSD apparait ici, meme sans lettre de lecteur, une recuperation logicielle est possible.' Add-Line '' Add-Result (Get-Disk | Select-Object Number, FriendlyName, SerialNumber, BusType, @{n='TailleGo';e={[math]::Round($_.Size/1GB,2)}}, PartitionStyle, OperationalStatus, HealthStatus | Format-Table -AutoSize) '>>> AUCUN DISQUE RETOURNE PAR Get-Disk <<<' Add-Section '3. DISQUES PHYSIQUES (Get-PhysicalDisk)' Add-Result (Get-PhysicalDisk | Select-Object DeviceId, FriendlyName, SerialNumber, MediaType, BusType, @{n='TailleGo';e={[math]::Round($_.Size/1GB,2)}}, HealthStatus, OperationalStatus | Format-Table -AutoSize) Add-Section '4. CONTROLEUR ET IDENTIFICATION BAS NIVEAU (Win32_DiskDrive)' Add-Line 'Point cle : un modele du type SATAFIRM S11, BAD_CTX, ou une taille de 0 / 2 Mo' Add-Line 'indique un controleur bloque en mode securite. Dans ce cas le logiciel ne peut rien.' Add-Line '' Add-Result (Get-CimInstance Win32_DiskDrive | Select-Object Index, Model, SerialNumber, FirmwareRevision, InterfaceType, @{n='TailleGo';e={[math]::Round($_.Size/1GB,2)}}, Partitions, Status, PNPDeviceID | Format-List) '>>> AUCUN DISQUE RETOURNE PAR Win32_DiskDrive <<<' # ----------------------------------------------------------- partitions ----- Add-Section '5. PARTITIONS' Add-Result (Get-Partition | Select-Object DiskNumber, PartitionNumber, DriveLetter, Type, IsHidden, @{n='TailleGo';e={[math]::Round($_.Size/1GB,2)}} | Format-Table -AutoSize) Add-Section '6. VOLUMES' Add-Result (Get-Volume | Select-Object DriveLetter, FileSystemLabel, FileSystem, HealthStatus, @{n='TailleGo';e={[math]::Round($_.Size/1GB,2)}}, @{n='LibreGo';e={[math]::Round($_.SizeRemaining/1GB,2)}} | Format-Table -AutoSize) # ------------------------------------------------------------- pnp state ---- Add-Section '7. PERIPHERIQUES DE STOCKAGE PRESENTS (etat pilote)' Add-Line 'Seuls les peripheriques actuellement branches sont listes.' Add-Line '' Add-Result (Get-PnpDevice -PresentOnly -Class DiskDrive, SCSIAdapter | Select-Object Status, Class, FriendlyName, InstanceId | Sort-Object Class, Status | Format-Table -AutoSize -Wrap) # -------------------------------------------------------- usb bridge ------- Add-Section '8. STOCKAGE USB (pont / adaptateur et disque associe)' Add-Line 'Un adaptateur USB vers SATA ou M.2 s enumere INDEPENDAMMENT du disque' Add-Line 'qu il contient. Les entrees USBSTOR ci dessous correspondent a un disque' Add-Line 'reellement vu DERRIERE le pont.' Add-Line '' Add-Result (Get-PnpDevice -PresentOnly | Where-Object { $_.InstanceId -like 'USBSTOR*' -or $_.InstanceId -like 'SCSI\DISK*' -or $_.FriendlyName -match 'stockage de masse|mass storage|UAS|USB Attached SCSI' } | Select-Object Status, Class, FriendlyName, InstanceId | Sort-Object Class | Format-Table -AutoSize -Wrap) '>>> AUCUN DISQUE VU DERRIERE UN PONT USB <<<' # ---------------------------------------------------- two-pass usb diff ----- $snapshotPath = Join-Path ([Environment]::GetFolderPath('Desktop')) 'techassist-usb-snapshot.csv' $currentUsb = Get-PnpDevice -PresentOnly | Where-Object { $_.InstanceId -like 'USB\*' -or $_.InstanceId -like 'USBSTOR*' -or $_.InstanceId -like 'SCSI\DISK*' } | Select-Object InstanceId, Class, FriendlyName, Status Add-Section '9. COMPARAISON DES DEUX PASSAGES (adaptateur vs support)' if ($isPass2) { if (Test-Path $snapshotPath) { $previous = Import-Csv $snapshotPath $newOnes = $currentUsb | Where-Object { $previous.InstanceId -notcontains $_.InstanceId } $gone = $previous | Where-Object { $currentUsb.InstanceId -notcontains $_.InstanceId } Add-Line 'Peripheriques APPARUS apres insertion du support :' Add-Line '(c est ici que le SSD doit se manifester)' Add-Line '' Add-Result ($newOnes | Select-Object Status, Class, FriendlyName, InstanceId | Format-Table -AutoSize -Wrap) '>>> AUCUN NOUVEAU PERIPHERIQUE <<<' Add-Line '' Add-Line 'Peripheriques DISPARUS entre les deux passages :' Add-Result ($gone | Select-Object Status, Class, FriendlyName, InstanceId | Format-Table -AutoSize -Wrap) 'Aucun.' Add-Line '' Add-Line 'LECTURE :' Add-Line ' - Rien de nouveau ET le pont USB present aux deux passages' Add-Line ' => l adaptateur fonctionne, le support ne repond pas.' Add-Line ' - Aucun pont USB present a aucun des deux passages' Add-Line ' => adaptateur, cable ou port USB en cause, pas le support.' Add-Line ' - Un nouveau peripherique apparait mais sans disque exploitable' Add-Line ' => le support repond mais son controleur refuse l acces.' } else { Add-Line 'Passage 1 introuvable. Relancez le script SANS le support pour la comparaison.' } } else { $currentUsb | Export-Csv -Path $snapshotPath -NoTypeInformation -Encoding UTF8 Add-Line ("Reference enregistree : " + ($currentUsb | Measure-Object).Count + " peripheriques USB presents.") Add-Line 'Relancez le script AVEC le support pour obtenir la comparaison.' Add-Line '' Add-Result ($currentUsb | Select-Object Status, Class, FriendlyName | Sort-Object Class | Format-Table -AutoSize -Wrap) } Add-Section '10. PERIPHERIQUES PRESENTS EN ERREUR' Add-Result (Get-PnpDevice -PresentOnly | Where-Object { $_.Status -in @('Error','Degraded','Unknown') } | Where-Object { $_.Class -in @('USB','DiskDrive','SCSIAdapter','Volume','WPD') } | Select-Object Status, Class, FriendlyName, InstanceId | Format-Table -AutoSize -Wrap) 'Aucun peripherique de stockage en erreur.' # ----------------------------------------------------------------- smart ---- Add-Section '11. ETAT SMART' Add-Result (Get-CimInstance -Namespace root\wmi -ClassName MSStorageDriver_FailurePredictStatus | Select-Object InstanceName, PredictFailure, Reason | Format-List) 'SMART indisponible sur cette machine.' Add-Section '12. COMPTEURS DE FIABILITE (necessite le mode admin)' if ($isAdmin) { Add-Result (Get-PhysicalDisk | ForEach-Object { $counters = $_ | Get-StorageReliabilityCounter if ($counters) { [pscustomobject]@{ Disque = $_.FriendlyName HeuresAllumage = $counters.PowerOnHours Temperature = $counters.Temperature UsureRestante = $_.Wear ErreursLecture = $counters.ReadErrorsTotal ErreursEcriture = $counters.WriteErrorsTotal } } } | Format-List) 'Aucun compteur disponible.' } else { Add-Line 'Section ignoree : relancez le script en tant qu administrateur pour l obtenir.' } # ------------------------------------------------------------ event log ----- Add-Section '13. ERREURS DISQUE ET USB DANS LE JOURNAL SYSTEME (30 derniers jours)' try { $events = Get-WinEvent -FilterHashtable @{ LogName = 'System' Level = 1, 2, 3 StartTime = (Get-Date).AddDays(-30) } | Where-Object { $_.ProviderName -match 'disk|storahci|stornvme|nvme|volmgr|ntfs|iaStor|USB|UASPStor|usbstor' } | Select-Object -First 40 TimeCreated, ProviderName, Id, Message Add-Result ($events | Format-List) 'Aucune erreur disque enregistree.' } catch { Add-Line 'Journal des evenements illisible sans le mode administrateur.' } # ------------------------------------------------------------- verdict ----- Add-Section '14. LECTURE RAPIDE' $diskCount = (Get-Disk | Measure-Object).Count $wmiCount = (Get-CimInstance Win32_DiskDrive | Measure-Object).Count Add-Line ("Nombre de disques physiques detectes : " + $diskCount + " (Get-Disk) / " + $wmiCount + " (WMI)") Add-Line '' Add-Line 'Comptez vos disques internes habituels. Si le total ci dessus inclut le support' Add-Line 'a recuperer, une recuperation logicielle est envisageable. Sinon, le support' Add-Line 'n est pas atteignable par logiciel et releve d une intervention materielle.' Add-Line '' if ($isPass2) { Add-Line 'Ceci est le passage 2. Pensez a joindre aussi le rapport du passage 1' Add-Line '(diagnostic-1-sans-support.txt), la comparaison des deux est indispensable.' } else { Add-Line 'Ceci est le passage 1. Relancez maintenant le script avec le support' Add-Line 'insere dans l adaptateur, puis envoyez les DEUX rapports.' } Add-Line '' Add-Line '--- Fin du rapport. Renvoyez ce fichier a contact@techassist-pro.com ---' # -------------------------------------------------------------- output ----- $lines | Out-File -FilePath $reportPath -Encoding utf8 Write-Host '' Write-Host " Passage termine ($passLabel)." -ForegroundColor Green Write-Host '' Write-Host ' Rapport enregistre sur votre Bureau :' Write-Host " $reportPath" -ForegroundColor Cyan Write-Host '' if ($isPass2) { Write-Host ' Envoyez les DEUX rapports a contact@techassist-pro.com' -ForegroundColor Yellow } else { Write-Host ' ETAPE SUIVANTE : inserez le support dans l adaptateur,' -ForegroundColor Yellow Write-Host ' relancez ce script et repondez O cette fois.' -ForegroundColor Yellow } Write-Host ''