151 lines
5.3 KiB
PowerShell
151 lines
5.3 KiB
PowerShell
<#
|
|
LXS - System Repair (Windows)
|
|
Description: Integrity repair for the component store and system files
|
|
(SFC, DISM, chkdsk). Requires administrator rights.
|
|
Repo: https://git.hyko.cx/hykocx/lxs
|
|
#>
|
|
|
|
# Load LXS common library (colors, UI helpers, spinner, loggers, guards).
|
|
# Prefers the sibling ..\lib\common.ps1 (repo checkout or installed layout) and
|
|
# only hits the network when this script is run standalone.
|
|
$LxsRawBase = if ($env:LXS_RAW_BASE) { $env:LXS_RAW_BASE } else { 'https://git.hyko.cx/hykocx/lxs/raw/branch/main' }
|
|
if (-not $env:LXS_RAW_PLATFORM_BASE) { $env:LXS_RAW_PLATFORM_BASE = "$LxsRawBase/windows" }
|
|
$LxsLibPath = if ($PSScriptRoot) { Join-Path $PSScriptRoot '..\lib\common.ps1' } else { $null }
|
|
if ($LxsLibPath -and (Test-Path $LxsLibPath)) {
|
|
. $LxsLibPath
|
|
} else {
|
|
try {
|
|
$LxsLibSource = Invoke-RestMethod -Uri "$env:LXS_RAW_PLATFORM_BASE/lib/common.ps1" -UseBasicParsing -ErrorAction Stop
|
|
} catch {
|
|
Write-Error 'Failed to fetch lib/common.ps1'
|
|
exit 1
|
|
}
|
|
. ([scriptblock]::Create($LxsLibSource))
|
|
}
|
|
|
|
$env:LXS_LOG_FILE = Join-Path (Get-LxsTempDir) 'lxs_repair.log'
|
|
|
|
if (-not (Assert-LxsWindows)) { exit 1 }
|
|
Assert-LxsAdmin -ScriptPath $PSCommandPath -Arguments $args
|
|
|
|
# These commands stream long-running progress; running them through the
|
|
# spinner would hide it, so they write straight to the console.
|
|
function Invoke-LxsRepairCommand {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$Title,
|
|
[Parameter(Mandatory = $true)][string]$Exe,
|
|
[Parameter(Mandatory = $true)][string[]]$CmdArgs,
|
|
[string]$Note = ''
|
|
)
|
|
Clear-Host
|
|
Show-LxsBoxTop -Title $Title
|
|
Write-Host ''
|
|
if ($Note) {
|
|
Write-Host "$($script:Gray)$Note$($script:NC)"
|
|
Write-Host ''
|
|
}
|
|
Write-LxsInfo "$Exe $($CmdArgs -join ' ')"
|
|
Show-LxsSeparator
|
|
Write-Host ''
|
|
|
|
& $Exe @CmdArgs
|
|
$code = $LASTEXITCODE
|
|
|
|
Write-Host ''
|
|
Show-LxsSeparator
|
|
if ($code -eq 0) {
|
|
Write-LxsOk "$Title completed"
|
|
} else {
|
|
Write-LxsWarn "$Title exited with code $code"
|
|
}
|
|
return $code
|
|
}
|
|
|
|
function Invoke-LxsSfc {
|
|
Invoke-LxsRepairCommand -Title 'SFC SCANNOW' -Exe 'sfc.exe' -CmdArgs @('/scannow') `
|
|
-Note 'Verifies every protected system file and repairs corrupted ones from the component store. Takes 5-15 minutes.' | Out-Null
|
|
}
|
|
|
|
function Invoke-LxsDism {
|
|
Clear-Host
|
|
Show-LxsBoxTop -Title 'DISM RESTOREHEALTH'
|
|
Write-Host ''
|
|
Write-Host "$($script:Gray)Repairs the component store itself. Run this before SFC when SFC$($script:NC)"
|
|
Write-Host "$($script:Gray)reports that it cannot fix files. Needs internet access for the$($script:NC)"
|
|
Write-Host "$($script:Gray)replacement payloads. Takes 10-30 minutes.$($script:NC)"
|
|
Write-Host ''
|
|
Show-LxsSeparator
|
|
Write-Host ''
|
|
|
|
Write-LxsInfo 'Step 1/3 - CheckHealth'
|
|
& dism.exe /Online /Cleanup-Image /CheckHealth
|
|
Write-Host ''
|
|
Write-LxsInfo 'Step 2/3 - ScanHealth (slow)'
|
|
& dism.exe /Online /Cleanup-Image /ScanHealth
|
|
Write-Host ''
|
|
Write-LxsInfo 'Step 3/3 - RestoreHealth'
|
|
& dism.exe /Online /Cleanup-Image /RestoreHealth
|
|
$code = $LASTEXITCODE
|
|
|
|
Write-Host ''
|
|
Show-LxsSeparator
|
|
if ($code -eq 0) { Write-LxsOk 'DISM completed' } else { Write-LxsWarn "DISM exited with code $code" }
|
|
}
|
|
|
|
function Invoke-LxsChkdsk {
|
|
Invoke-LxsRepairCommand -Title 'CHKDSK SCAN' -Exe 'chkdsk.exe' -CmdArgs @($env:SystemDrive, '/scan') `
|
|
-Note 'Online, read-only scan of the system volume. It reports problems without taking the volume offline; a full /f repair needs a reboot.' | Out-Null
|
|
}
|
|
|
|
function Invoke-LxsFullRepair {
|
|
Clear-Host
|
|
Show-LxsBoxTop -Title 'FULL REPAIR PASS'
|
|
Write-Host ''
|
|
Write-Host 'Runs, in the recommended order:'
|
|
Write-Host ' 1. DISM /RestoreHealth (repair the component store)'
|
|
Write-Host ' 2. SFC /scannow (repair system files from that store)'
|
|
Write-Host ' 3. chkdsk /scan (check the file system)'
|
|
Write-Host ''
|
|
Write-Host "$($script:Gray)Budget 30-60 minutes. Nothing here is destructive.$($script:NC)"
|
|
Write-Host ''
|
|
if (-not (Confirm-LxsAction -Question 'Start the full repair pass?' -DefaultYes)) {
|
|
Write-LxsInfo 'Cancelled.'
|
|
return
|
|
}
|
|
Invoke-LxsDism
|
|
Read-LxsEnter
|
|
Invoke-LxsSfc
|
|
Read-LxsEnter
|
|
Invoke-LxsChkdsk
|
|
}
|
|
|
|
function Show-LxsRepairMenu {
|
|
while ($true) {
|
|
Clear-Host
|
|
Show-LxsBoxTop -Title 'SYSTEM REPAIR' -Right 'ADMIN'
|
|
Write-Host ''
|
|
Show-LxsMenuItem '1' 'SFC /scannow' 'repair system files'
|
|
Show-LxsMenuItem '2' 'DISM /RestoreHealth' 'repair component store'
|
|
Show-LxsMenuItem '3' 'chkdsk /scan' 'check the file system'
|
|
Show-LxsMenuItem '4' 'Full repair pass' 'DISM, then SFC, then chkdsk'
|
|
Show-LxsMenuItem '0' 'Back' '' -Exit
|
|
Write-Host ''
|
|
Show-LxsBoxBottom
|
|
Write-Host ''
|
|
$choice = Read-LxsChoice
|
|
Write-Host ''
|
|
|
|
switch ($choice) {
|
|
'1' { Invoke-LxsSfc; Read-LxsEnter }
|
|
'2' { Invoke-LxsDism; Read-LxsEnter }
|
|
'3' { Invoke-LxsChkdsk; Read-LxsEnter }
|
|
'4' { Invoke-LxsFullRepair; Read-LxsEnter }
|
|
'0' { return }
|
|
default { Write-LxsErr 'Invalid protocol. Select 0-4.'; Start-Sleep -Seconds 1 }
|
|
}
|
|
}
|
|
}
|
|
|
|
Show-LxsRepairMenu
|
|
exit 75
|