remove nested helper and use single locale-safe parser
- Delete inline Invoke-DismWithProgress inside Invoke-WindowsUpdateRepair - Keep one global helper with integer-only % parsing (handles “4.9%”, “4,9%”)
This commit is contained in:
105
SRGAdminMenu.ps1
105
SRGAdminMenu.ps1
@ -125,53 +125,17 @@ function Remove-ProvisionedAndExisting {
|
||||
function Invoke-WindowsUpdateRepair {
|
||||
param([string]$Computer)
|
||||
|
||||
$sb = {
|
||||
$isLocal = [string]::IsNullOrWhiteSpace($Computer) -or $Computer -in @('localhost','127.0.0.1','.')
|
||||
|
||||
if ($isLocal) {
|
||||
# ==== LOCAL run (with real progress) ====
|
||||
function Test-Admin {
|
||||
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$p = New-Object Security.Principal.WindowsPrincipal($id)
|
||||
$p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
if (-not (Test-Admin)) { throw "You must run this elevated (Administrator)." }
|
||||
|
||||
# Local helper for progress (only available when running locally)
|
||||
function Invoke-DismWithProgress {
|
||||
param([string[]]$Arguments)
|
||||
$ts = Get-Date -Format 'yyyyMMdd_HHmmss'
|
||||
$outf = Join-Path $env:TEMP "dism_out_$ts.txt"
|
||||
$errf = Join-Path $env:TEMP "dism_err_$ts.txt"
|
||||
if (-not ($Arguments -match '/LogPath:')) {
|
||||
$logFile = Join-Path $env:TEMP "dism_log_$ts.log"
|
||||
$Arguments += "/LogPath:$logFile"
|
||||
}
|
||||
$p = Start-Process dism.exe -ArgumentList ($Arguments -join ' ') -NoNewWindow -RedirectStandardOutput $outf -RedirectStandardError $errf -PassThru
|
||||
$lastPct = -1
|
||||
while (-not $p.HasExited) {
|
||||
if (Test-Path $outf) {
|
||||
$content = Get-Content $outf -Raw -ErrorAction SilentlyContinue
|
||||
if ($content) {
|
||||
$m = [regex]::Matches($content, '(\d{1,3}(?:\.\d+)?)%')
|
||||
if ($m.Count -gt 0) {
|
||||
$pct = [int][math]::Min(100, [double]$m[$m.Count-1].Value)
|
||||
if ($pct -ne $lastPct) {
|
||||
Write-Progress -Activity "DISM $($Arguments -join ' ')" -Status "$pct%" -PercentComplete $pct
|
||||
$lastPct = $pct
|
||||
}
|
||||
} else {
|
||||
Write-Progress -Activity "DISM $($Arguments -join ' ')" -Status "Working..." -PercentComplete 0
|
||||
}
|
||||
}
|
||||
}
|
||||
Start-Sleep -Milliseconds 400
|
||||
}
|
||||
Write-Progress -Activity "DISM $($Arguments -join ' ')" -Completed
|
||||
if ($p.ExitCode -ne 0) {
|
||||
Write-Warning "DISM exited with code $($p.ExitCode)"
|
||||
if (Test-Path $errf) { Get-Content $errf -Tail 25 | Write-Warning }
|
||||
}
|
||||
return $p.ExitCode
|
||||
}
|
||||
|
||||
Write-Host "=== Step 1: DISM (ScanHealth) ===" -ForegroundColor Cyan
|
||||
$e1 = Invoke-DismWithProgress -Arguments @('/Online','/Cleanup-Image','/ScanHealth')
|
||||
if ($e1 -ne 0) { throw "DISM ScanHealth failed with code $e1" }
|
||||
@ -190,8 +154,8 @@ function Invoke-WindowsUpdateRepair {
|
||||
$sd = Join-Path $env:SystemRoot 'SoftwareDistribution'
|
||||
$cat = Join-Path $env:SystemRoot 'System32\catroot2'
|
||||
$ts = Get-Date -Format 'yyyyMMdd_HHmmss'
|
||||
if (Test-Path $sd) { try { Rename-Item $sd ("SoftwareDistribution.bak_$ts") -ErrorAction Stop } catch { } }
|
||||
if (Test-Path $cat) { try { Rename-Item $cat ("catroot2.bak_$ts") -ErrorAction Stop } catch { } }
|
||||
if (Test-Path $sd) { try { Rename-Item -Path $sd -NewName ("SoftwareDistribution.bak_$ts") -ErrorAction Stop } catch { } }
|
||||
if (Test-Path $cat) { try { Rename-Item -Path $cat -NewName ("catroot2.bak_$ts") -ErrorAction Stop } catch { } }
|
||||
foreach ($s in $services) { try { Start-Service -Name $s -ErrorAction Stop } catch { } }
|
||||
|
||||
Write-Host "`n=== Step 4: Trigger update scan ===" -ForegroundColor Cyan
|
||||
@ -204,16 +168,51 @@ function Invoke-WindowsUpdateRepair {
|
||||
)) { try { & $cmd | Out-Null } catch { } }
|
||||
|
||||
Write-Host "`nWindows Update repair sequence completed." -ForegroundColor Green
|
||||
return
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Computer) -or $Computer -in @('localhost','127.0.0.1','.')) {
|
||||
& $sb
|
||||
} else {
|
||||
# Over remoting, Write-Progress doesn't render well<6C>still run the repair,
|
||||
# but you'll see normal text output. (If you want, we can add a remote-side
|
||||
# log tail that writes periodic progress messages.)
|
||||
Invoke-Remote -Computer $Computer -ScriptBlock $sb
|
||||
# ==== REMOTE run ====
|
||||
$sb = {
|
||||
function Test-Admin {
|
||||
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$p = New-Object Security.Principal.WindowsPrincipal($id)
|
||||
return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
if (-not (Test-Admin)) { throw "You must run this elevated (Administrator)." }
|
||||
|
||||
Write-Host "=== Step 1: DISM (ScanHealth) ==="
|
||||
& dism.exe /Online /Cleanup-Image /ScanHealth | Out-Host
|
||||
|
||||
Write-Host "`n=== Step 1b: DISM (RestoreHealth) ==="
|
||||
& dism.exe /Online /Cleanup-Image /RestoreHealth /NoRestart | Out-Host
|
||||
|
||||
Write-Host "`n=== Step 2: SFC ==="
|
||||
& sfc.exe /scannow | Out-Host
|
||||
|
||||
Write-Host "`n=== Step 3: Reset Windows Update components ==="
|
||||
$services = 'wuauserv','bits','cryptsvc','msiserver'
|
||||
foreach ($s in $services) { try { Stop-Service -Name $s -Force -ErrorAction Stop } catch { } }
|
||||
|
||||
$sd = Join-Path $env:SystemRoot 'SoftwareDistribution'
|
||||
$cat = Join-Path $env:SystemRoot 'System32\catroot2'
|
||||
$ts = Get-Date -Format 'yyyyMMdd_HHmmss'
|
||||
if (Test-Path $sd) { try { Rename-Item -Path $sd -NewName ("SoftwareDistribution.bak_$ts") -ErrorAction Stop } catch { } }
|
||||
if (Test-Path $cat) { try { Rename-Item -Path $cat -NewName ("catroot2.bak_$ts") -ErrorAction Stop } catch { } }
|
||||
foreach ($s in $services) { try { Start-Service -Name $s -ErrorAction Stop } catch { } }
|
||||
|
||||
Write-Host "`n=== Step 4: Trigger update scan ==="
|
||||
foreach ($cmd in @(
|
||||
{ & usoclient.exe StartScan },
|
||||
{ & usoclient.exe StartDownload },
|
||||
{ & usoclient.exe StartInstall },
|
||||
{ & wuauclt.exe /detectnow },
|
||||
{ & wuauclt.exe /reportnow }
|
||||
)) { try { & $cmd | Out-Null } catch { } }
|
||||
|
||||
Write-Host "`nWindows Update repair sequence completed."
|
||||
}
|
||||
|
||||
Invoke-Remote -Computer $Computer -ScriptBlock $sb
|
||||
}
|
||||
|
||||
function Invoke-DismWithProgress {
|
||||
@ -247,11 +246,11 @@ function Invoke-DismWithProgress {
|
||||
if (Test-Path $outf) {
|
||||
$content = Get-Content -Path $outf -Raw -ErrorAction SilentlyContinue
|
||||
if ($content) {
|
||||
# Capture "NN", optionally followed by decimal with . or , then %
|
||||
# Examples matched: "4.9%", "4,9 %", "62%" -> group 1 = integer part
|
||||
# Match "NN", optional decimal with . or , then %, allowing whitespace
|
||||
# Examples: "4.9%", "4,9 %", "62%"
|
||||
$m = [regex]::Matches($content, '(\d{1,3})(?:[.,]\d+)?\s*%')
|
||||
if ($m.Count -gt 0) {
|
||||
$pctText = $m[$m.Count-1].Groups[1].Value
|
||||
$pctText = $m[$m.Count-1].Groups[1].Value # integer part only
|
||||
$pct = 0
|
||||
[void][int]::TryParse($pctText, [ref]$pct)
|
||||
if ($pct -gt 100) { $pct = 100 }
|
||||
|
||||
Reference in New Issue
Block a user