Public/Repair-CMClient.ps1

function Repair-CMClient {
    <#
    .SYNOPSIS
        Remediates a ConfigMgr client: WMI RepairClient, service restart, or ccmsetup reinstall.
    .DESCRIPTION
        Method RepairClient : invokes SMS_Client.RepairClient (runs ccmrepair.exe). Least invasive.
        Method RestartService: restarts CcmExec via Invoke-Command.
        Method Reinstall : runs ccmsetup.exe from \\SiteServer\SMS_<SiteCode>\Client with /forceinstall.
        All methods are gated by ShouldProcess with ConfirmImpact High.
    .PARAMETER ComputerName
        Target computers.
    .PARAMETER Method
        RepairClient (default), RestartService, Reinstall.
    .PARAMETER SiteCode
        Site code (Reinstall).
    .PARAMETER SiteServer
        Site server hosting the client source share (Reinstall).
    .PARAMETER ManagementPoint
        Optional MP passed as /mp: (Reinstall).
    .EXAMPLE
        Repair-CMClient -ComputerName PC01 -WhatIf
    .EXAMPLE
        Repair-CMClient -ComputerName PC01 -Method Reinstall -SiteCode HOU -SiteServer cm01.contoso.com
    .NOTES
        Reinstall copies ccmsetup from the share inside the remote session; this requires CredSSP/Kerberos
        delegation or a share readable by the target computer account. Lab-test first.
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    param(
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)][Alias('Name')][string[]]$ComputerName,
        [ValidateSet('RepairClient','RestartService','Reinstall')][string]$Method = 'RepairClient',
        [string]$SiteCode,
        [Alias('ProviderMachineName')][string]$SiteServer,
        [string]$ManagementPoint
    )
    begin {
        if ($Method -eq 'Reinstall' -and (-not $SiteCode -or -not $SiteServer)) {
            throw 'Reinstall requires -SiteCode and -SiteServer.'
        }
    }
    process {
        foreach ($c in $ComputerName) {
            if (-not $PSCmdlet.ShouldProcess($c, "Repair ConfigMgr client ($Method)")) { continue }
            try {
                switch ($Method) {
                    'RepairClient' {
                        Invoke-CimMethod -ComputerName $c -Namespace root\ccm -ClassName SMS_Client -MethodName RepairClient -ErrorAction Stop | Out-Null
                    }
                    'RestartService' {
                        Invoke-Command -ComputerName $c -ErrorAction Stop -ScriptBlock { Restart-Service -Name CcmExec -Force }
                    }
                    'Reinstall' {
                        $src = "\\$SiteServer\SMS_$SiteCode\Client\ccmsetup.exe"
                        $setupArgs = @('/forceinstall', "SMSSITECODE=$SiteCode")
                        if ($ManagementPoint) { $setupArgs = @("/mp:$ManagementPoint") + $setupArgs }
                        Invoke-Command -ComputerName $c -ErrorAction Stop -ArgumentList $src, $setupArgs -ScriptBlock {
                            param($src, $a)
                            $dst = Join-Path $env:TEMP 'ccmsetup.exe'
                            Copy-Item -LiteralPath $src -Destination $dst -Force
                            Start-Process -FilePath $dst -ArgumentList $a -WindowStyle Hidden
                        }
                    }
                }
                [pscustomobject]@{ ComputerName = $c; Method = $Method; Result = 'Started' }
            } catch {
                [pscustomobject]@{ ComputerName = $c; Method = $Method; Result = "Failed: $($_.Exception.Message)" }
            }
        }
    }
}