MECM: Client check

Just another Tech site

MECM: Client check

Updating to a new client and want to check to make sure the client is working correctly.

 

<#
    SCCM Health Check Script
    - Validates SCCM client health
    - Logging + summary report
    - Designed to pair with removal/reinstall scripts
#>

# ============================
# Logging + Summary Functions
# ============================

$Global:LogFile = "C:\Windows\Temp\SCCM_HealthCheck_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
$Global:Summary = @()

function Write-Log {
    param(
        [string]$Message,
        [string]$Level = "INFO"
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $entry = "[$timestamp] [$Level] $Message"

    Write-Host $entry
    Add-Content -Path $Global:LogFile -Value $entry
}

function Add-Summary {
    param([string]$Message)
    $Global:Summary += $Message
}

# ============================
# Health Check Function
# ============================

function Test-SCCMHealth {

    Write-Log "Starting SCCM health check..."
    Add-Summary "Health check started"

    # ----------------------------
    # 1. Check if SCCM is installed
    # ----------------------------
    Write-Log "Checking for SCCM installation..."

    $ccmExecService = Get-Service -Name CcmExec -ErrorAction SilentlyContinue

    if (-not $ccmExecService) {
        Write-Log "SCCM client is NOT installed." "WARN"
        Add-Summary "Client not installed"
        return
    }

    Add-Summary "Client installed"

    # ----------------------------
    # 2. Check CcmExec service
    # ----------------------------
    Write-Log "Checking CcmExec service status..."

    if ($ccmExecService.Status -eq "Running") {
        Write-Log "CcmExec service is running."
        Add-Summary "CcmExec running"
    }
    else {
        Write-Log "CcmExec service is NOT running." "ERROR"
        Add-Summary "CcmExec NOT running"
    }

    # ----------------------------
    # 3. Check WMI repository
    # ----------------------------
    Write-Log "Checking WMI repository consistency..."

    $verify = (winmgmt /verifyrepository)

    if ($verify -match "consistent") {
        Write-Log "WMI repository is consistent."
        Add-Summary "WMI healthy"
    }
    else {
        Write-Log "WMI repository is NOT consistent." "ERROR"
        Add-Summary "WMI inconsistent"
    }

    # ----------------------------
    # 4. Check SCCM WMI namespaces
    # ----------------------------
    Write-Log "Checking SCCM WMI namespaces..."

    $namespaces = @(
        "root\ccm",
        "root\ccm\policy",
        "root\ccm\softwareinventory",
        "root\ccm\hardwareinventory",
        "root\ccm\locationservices"
    )

    foreach ($ns in $namespaces) {
        try {
            Get-CimInstance -Namespace $ns -ClassName __Namespace -ErrorAction Stop | Out-Null
            Write-Log "Namespace OK: $ns"
            Add-Summary "WMI OK: $ns"
        }
        catch {
            Write-Log "Namespace missing: $ns" "ERROR"
            Add-Summary "WMI missing: $ns"
        }
    }

    # ----------------------------
    # 5. Check client assignment
    # ----------------------------
    Write-Log "Checking client assignment..."

    try {
        $ls = Get-CimInstance -Namespace "root\ccm\locationservices" -ClassName "SMS_LocationServices" -ErrorAction Stop
        $assignedSite = $ls.SMSAssignedSiteCode
        $mp = $ls.CurrentManagementPoint

        Write-Log "Assigned Site: $assignedSite"
        Write-Log "Management Point: $mp"

        Add-Summary "Assigned Site: $assignedSite"
        Add-Summary "MP: $mp"
    }
    catch {
        Write-Log "Unable to query SMS_LocationServices." "ERROR"
        Add-Summary "Client assignment check failed"
    }

    # ----------------------------
    # 6. Check registry keys
    # ----------------------------
    Write-Log "Checking registry keys..."

    $regPath = "HKLM:\SOFTWARE\Microsoft\CCM"

    if (Test-Path $regPath) {
        Write-Log "Registry key exists: $regPath"
        Add-Summary "Registry OK"
    }
    else {
        Write-Log "Registry key missing: $regPath" "ERROR"
        Add-Summary "Registry missing"
    }

    # ----------------------------
    # 7. Check certificates
    # ----------------------------
    Write-Log "Checking SCCM certificates..."

    $certs = Get-ChildItem Cert:\LocalMachine\SMS -ErrorAction SilentlyContinue

    if ($certs) {
        Write-Log "SCCM certificates found."
        Add-Summary "Certificates OK"
    }
    else {
        Write-Log "No SCCM certificates found." "WARN"
        Add-Summary "Certificates missing"
    }

    # ----------------------------
    # 8. Check CCM folder structure (Completed)
    # ----------------------------
    Write-Log "Checking CCM folder structure..."

    $ccmRoot = "$Env:WinDir\CCM"

    if (Test-Path $ccmRoot) {
        Write-Log "CCM root folder exists."
        Add-Summary "CCM folder OK"
    } else {
        Write-Log "CCM folder missing." "ERROR"
        Add-Summary "CCM folder missing"
        return
    }

    # Required subfolders
    $requiredSubfolders = @(
        "Logs",
        "Cache",
        "Inventory",
        "ServiceData"
    )

    foreach ($sub in $requiredSubfolders) {
        $path = Join-Path $ccmRoot $sub
        if (Test-Path $path) {
            Write-Log "Subfolder OK: $sub"
            Add-Summary "Subfolder OK: $sub"
        } else {
            Write-Log "Missing subfolder: $sub" "WARN"
            Add-Summary "Missing subfolder: $sub"
        }
    }

    # Required core files
    $requiredFiles = @(
        "CcmExec.exe",
        "CcmRepair.exe",
        "CcmRestart.exe",
        "CcmEval.exe"
    )

    foreach ($file in $requiredFiles) {
        $path = Join-Path $ccmRoot $file
        if (Test-Path $path) {
            Write-Log "File OK: $file"
            Add-Summary "File OK: $file"
        } else {
            Write-Log "Missing file: $file" "ERROR"
            Add-Summary "Missing file: $file"
        }
    }

    # Check version of CcmExec.exe
    $ccmExecPath = Join-Path $ccmRoot "CcmExec.exe"

    if (Test-Path $ccmExecPath) {
        $version = (Get-Item $ccmExecPath).VersionInfo.FileVersion
        Write-Log "CcmExec.exe version: $version"
        Add-Summary "CcmExec version: $version"
    } else {
        Write-Log "CcmExec.exe missing — cannot determine version." "ERROR"
        Add-Summary "CcmExec missing"
    }

    Write-Log "Health check completed."
    Add-Summary "Health check completed"
}

# ============================
# Run Health Check
# ============================

Test-SCCMHealth

# ============================
# Summary Report
# ============================

Write-Log "Generating summary report..."

$summaryHeader = "===== SCCM Health Check Summary ====="
Write-Host $summaryHeader
Add-Content -Path $Global:LogFile -Value $summaryHeader

foreach ($item in $Global:Summary) {
    Write-Host " - $item"
    Add-Content -Path $Global:LogFile -Value " - $item"
}

$summaryFooter = "===== End of Summary ====="
Write-Host $summaryFooter
Add-Content -Path $Global:LogFile -Value $summaryFooter

Write-Log "Summary report completed. Log saved to $Global:LogFile"