Public/Invoke-TechCareRepair.ps1

function Invoke-TechCareRepair {
    <#
    .SYNOPSIS
        Repara la imagen del sistema y los archivos protegidos de Windows.
    .DESCRIPTION
        Ejecuta DISM /RestoreHealth, despues sfc /scannow y por ultimo chkdsk en
        modo escaneo. chkdsk se lanza con /scan, que es solo lectura y en linea:
        no repara, no desmonta el volumen y no programa un reinicio.

        Requiere administrador. Sin elevacion devuelve estado Gris y no intenta
        nada, porque DISM sin privilegios falla a medias.
    .PARAMETER SkipChkdsk
        Omite el escaneo de chkdsk, que es la fase mas larga en discos grandes.
    .EXAMPLE
        Invoke-TechCareRepair -WhatIf

        Muestra las tres fases que se ejecutarian sin tocar nada.
    .EXAMPLE
        Invoke-TechCareRepair -Confirm:$false

        Ejecuta las tres fases sin pedir confirmacion por cada una.
    .EXAMPLE
        Invoke-TechCareRepair -SkipChkdsk -Confirm:$false

        Repara imagen y archivos protegidos, sin escanear el volumen.
    .OUTPUTS
        PSCustomObject
    .LINK
        https://github.com/earbona23/TechCare
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    [OutputType([pscustomobject])]
    param(
        [switch]$SkipChkdsk
    )

    if (-not (Test-TechCarePlatform)) { throw $script:PlatformMessage }

    $findings = New-Object -TypeName System.Collections.ArrayList
    $actions  = New-Object -TypeName System.Collections.ArrayList
    $recs     = New-Object -TypeName System.Collections.ArrayList
    $status   = 'Green'
    $mod      = 'Repair'

    if (-not (Test-TechCareAdmin)) {
        [void]$findings.Add('Sin privilegios de administrador: Repair omitido.')
        [void]$recs.Add('Relanzar la consola como administrador para ejecutar Repair.')
        Write-TechCareLog -ModuleName $mod -Level Warning -Message 'Repair omitido por falta de privilegios.'
        return Add-TechCareResult -Module $mod -Status 'Gray' -Findings $findings.ToArray() -Recommendations $recs.ToArray()
    }

    $dism   = Join-Path -Path $env:SystemRoot -ChildPath 'System32\DISM.exe'
    $sfc    = Join-Path -Path $env:SystemRoot -ChildPath 'System32\sfc.exe'
    $chkdsk = Join-Path -Path $env:SystemRoot -ChildPath 'System32\chkdsk.exe'

    if ($PSCmdlet.ShouldProcess('Imagen de Windows', 'DISM /Online /Cleanup-Image /RestoreHealth')) {
        Write-Progress -Activity 'TechCare' -Status 'DISM RestoreHealth' -PercentComplete 20
        Write-TechCareLog -ModuleName $mod -Message 'Ejecutando DISM RestoreHealth (puede tardar varios minutos, no lo interrumpas).'
        $r = Invoke-TechCareProcess -FilePath $dism -ArgumentList @('/Online', '/Cleanup-Image', '/RestoreHealth')
        if ($r.ExitCode -eq 0) {
            [void]$actions.Add('DISM RestoreHealth completado (codigo 0).')
        } elseif ($r.ExitCode -eq 3010) {
            # 3010 es ERROR_SUCCESS_REBOOT_REQUIRED: la reparacion funciono.
            [void]$actions.Add('DISM RestoreHealth completado; requiere reinicio (3010).')
            [void]$recs.Add('Reiniciar para consolidar la reparacion de imagen.')
        } else {
            $status = 'Yellow'
            [void]$findings.Add(('DISM devolvio codigo {0}.' -f $r.ExitCode))
            [void]$recs.Add('Revisar %WinDir%\Logs\CBS\CBS.log si DISM persiste en fallo.')
            Write-TechCareLog -ModuleName $mod -Level Warning -Message 'DISM con codigo distinto de 0.' -ErrorText $r.Output
        }
    }

    if ($PSCmdlet.ShouldProcess('Archivos protegidos del sistema', 'sfc /scannow')) {
        Write-Progress -Activity 'TechCare' -Status 'sfc /scannow' -PercentComplete 55
        Write-TechCareLog -ModuleName $mod -Message 'Ejecutando sfc /scannow.'
        $r = Invoke-TechCareProcess -FilePath $sfc -ArgumentList @('/scannow')
        # sfc esta localizado y no distingue sus casos por codigo de salida, asi
        # que hay que leer el texto. Se cubren espanol e ingles; cualquier otro
        # idioma cae en la rama no concluyente y queda registrado en bruto.
        if ($r.Output -match 'no ha encontrado|did not find any integrity violations') {
            [void]$actions.Add('sfc: sin infracciones de integridad.')
        } elseif ($r.Output -match 'reparado correctamente|successfully repaired') {
            $status = 'Yellow'
            [void]$actions.Add('sfc: archivos danados reparados.')
            [void]$recs.Add('Hubo dano en archivos del sistema: vigilar el equipo los proximos dias.')
        } elseif ($r.Output -match 'no pudo reparar|unable to fix') {
            $status = 'Yellow'
            [void]$findings.Add('sfc detecto dano que no pudo reparar.')
            [void]$recs.Add('Revisar CBS.log y valorar una reparacion in-place de Windows.')
        } else {
            [void]$actions.Add('sfc ejecutado; salida no concluyente, registrada en el log.')
        }
        Write-TechCareLog -ModuleName $mod -Level Detail -Message 'Salida de sfc registrada.' -ErrorText $r.Output
    }

    if (-not $SkipChkdsk) {
        $target = $env:SystemDrive
        if ($PSCmdlet.ShouldProcess(('Volumen {0}' -f $target), 'chkdsk /scan (solo lectura, sin reinicio)')) {
            Write-Progress -Activity 'TechCare' -Status 'chkdsk /scan' -PercentComplete 80
            Write-TechCareLog -ModuleName $mod -Message ('Escaneo chkdsk en {0} (sin reparacion).' -f $target)
            $r = Invoke-TechCareProcess -FilePath $chkdsk -ArgumentList @($target, '/scan')
            if ($r.ExitCode -eq 0) {
                [void]$actions.Add('chkdsk /scan sin problemas detectados.')
            } else {
                $status = 'Yellow'
                [void]$findings.Add(('chkdsk /scan devolvio codigo {0}.' -f $r.ExitCode))
                [void]$recs.Add('Ejecutar chkdsk /spotfix en ventana de mantenimiento si procede. TechCare no lo hace por ti: /spotfix bloquea el volumen.')
            }
            Write-TechCareLog -ModuleName $mod -Level Detail -Message 'Salida de chkdsk registrada.' -ErrorText $r.Output
        }
    } else {
        [void]$findings.Add('chkdsk omitido por -SkipChkdsk.')
    }

    Write-Progress -Activity 'TechCare' -Status 'Reparacion completada' -Completed
    return Add-TechCareResult -Module $mod -Status $status -Findings $findings.ToArray() -Actions $actions.ToArray() -Recommendations $recs.ToArray()
}