Public/Get-VBSyncCenterStatus.ps1

# ============================================================
# FUNCTION : Get-VBSyncCenterStatus
# MODULE : WorkstationReport
# VERSION : 1.3.1
# CHANGED : 14-04-2026 -- Standards compliance fixes
# AUTHOR : Vibhu Bhatnagar
# PURPOSE : Retrieves Windows Sync Center (CSC) configuration and status
# ENCODING : UTF-8 with BOM
# ============================================================

function Get-VBSyncCenterStatus {
    <#
    .SYNOPSIS
    Retrieves the Windows Sync Center (Offline Files / CSC) configuration and status.
 
    .DESCRIPTION
    Get-VBSyncCenterStatus examines the Windows Client Side Caching (CSC) subsystem by
    querying registry settings, WMI/CIM classes, and the cache directory. It reports on
    Group Policy configuration, the CSC driver and service startup types, cache active/
    enabled state, cache location, file count, and optionally the full list of cached files.
 
    A single scriptblock is used for both local and remote execution to eliminate code
    duplication -- local runs use direct invocation (&), remote runs use Invoke-Command.
 
    .PARAMETER ComputerName
    Computer names to query. Accepts pipeline input. Defaults to the local computer.
 
    .PARAMETER Credential
    Credentials for remote computer access. Not required for local execution.
 
    .PARAMETER IncludeFileList
    When specified, includes an array of all cached file paths in the output.
    May impact performance on systems with a large cache.
 
    .EXAMPLE
    Get-VBSyncCenterStatus
 
    Returns Sync Center status for the local computer.
 
    .EXAMPLE
    Get-VBSyncCenterStatus -ComputerName 'WS001','WS002' -Credential (Get-Credential)
 
    Returns Sync Center status for two remote workstations using alternate credentials.
 
    .EXAMPLE
    'WS001' | Get-VBSyncCenterStatus -IncludeFileList
 
    Queries a remote computer via pipeline and includes the full list of cached files.
 
    .EXAMPLE
    Get-VBSyncCenterStatus -ComputerName $computers -Credential $cred |
        Where-Object { $_.CSCStatus -ne 'Disabled' } |
        Select-Object ComputerName, CSCStatus, CacheEnabled, FileCount
 
    Finds all machines where CSC is not disabled and reports key fields.
 
    .OUTPUTS
    PSCustomObject
    Returns an object with:
    - ComputerName : Target computer
    - NetCachePolicy : Group Policy setting ('Not Set', 'Enabled', 'Disabled', 'Unknown')
    - CSCServiceStatus : CscService startup type ('Automatic', 'Disabled', 'Unknown')
    - CSCStatus : CSC driver startup type ('System', 'Disabled', 'Unknown')
    - CacheActive : Boolean -- whether the cache is currently active
    - CacheEnabled : Boolean -- whether offline files is enabled
    - CacheLocation : Filesystem path to the CSC cache directory
    - FileCount : Number of files found in the cache directory
    - GroupPolicyName : GPO ID applying the NetCache policy (if any)
    - FileList : Array of cached file paths (empty unless -IncludeFileList used)
    - CollectionTime : Timestamp of data collection
    - Status : 'Success' or 'Failed'
    - Error : Error message (only present on failure)
 
    .NOTES
    Version : 1.3.1
    Author : Vibhu Bhatnagar
    Category: Windows Workstation Administration
 
    Requirements:
    - PowerShell 5.1 or higher
    - Administrative privileges for full registry and CIM access
    - PowerShell Remoting enabled for remote targets
    #>


    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('Name', 'Server', 'Host')]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        [PSCredential]$Credential,

        [switch]$IncludeFileList
    )

    process {
        # Core logic defined once -- executed locally or via Invoke-Command
        $scriptBlock = {
            param([bool]$IncludeFiles)

            $cscStart       = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\CSC' `
                -Name 'Start' -ErrorAction SilentlyContinue
            $cscServiceStart = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\CscService' `
                -Name 'Start' -ErrorAction SilentlyContinue
            $netCacheEnabled = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\NetCache' `
                -Name 'Enabled' -ErrorAction SilentlyContinue
            $cacheLocationReg = Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Services\CSC' `
                -Name 'CacheLocation' -ErrorAction SilentlyContinue
            $cacheInfo       = Get-CimInstance -ClassName Win32_OfflineFilesCache -ErrorAction SilentlyContinue

            # Group Policy identification
            $gpoName = 'Not Set'
            try {
                $gpResult = Get-CimInstance -ClassName RSOP_RegistryPolicySetting `
                    -Namespace 'root\rsop\computer' `
                    -Filter "registryKey like '%NetCache%'" -ErrorAction SilentlyContinue
                if ($gpResult) { $gpoName = $gpResult.GPOID }
            }
            catch {
                $gpoName = 'Unable to determine'
            }

            $cacheLocation = if ($cacheLocationReg.CacheLocation) {
                $cacheLocationReg.CacheLocation
            }
            else { 'C:\Windows\CSC' }

            # Cache file enumeration
            $fileCount = 0
            $fileList  = @()
            if (Test-Path $cacheLocation) {
                try {
                    $files     = Get-ChildItem -Path $cacheLocation -Recurse -File -ErrorAction SilentlyContinue
                    $fileCount = ($files | Measure-Object).Count
                    if ($IncludeFiles -and $files) {
                        $fileList = $files | Select-Object -ExpandProperty FullName
                    }
                }
                catch {
                    $fileCount = 0
                }
            }

            return @{
                CSCStart        = $cscStart
                CSCServiceStart = $cscServiceStart
                NetCacheEnabled = $netCacheEnabled
                CacheInfo       = $cacheInfo
                GPOName         = $gpoName
                CacheLocation   = $cacheLocation
                FileCount       = $fileCount
                FileList        = $fileList
            }
        }

        foreach ($computer in $ComputerName) {
            try {
                Write-Verbose "Querying Sync Center status on: $computer"

                $includeFiles = $IncludeFileList.IsPresent

                if ($computer -eq $env:COMPUTERNAME) {
                    $data = & $scriptBlock $includeFiles
                }
                else {
                    $invokeParams = @{
                        ComputerName = $computer
                        ScriptBlock  = $scriptBlock
                        ArgumentList = $includeFiles
                        ErrorAction  = 'Stop'
                    }
                    if ($Credential) { $invokeParams['Credential'] = $Credential }
                    $data = Invoke-Command @invokeParams
                }

                # Translate registry values to human-readable strings
                $netCachePolicyStatus = switch ($data.NetCacheEnabled.Enabled) {
                    $null { 'Not Set' }
                    0     { 'Disabled' }
                    1     { 'Enabled' }
                    default { 'Unknown' }
                }

                $cscServiceStatus = switch ($data.CSCServiceStart.Start) {
                    2       { 'Automatic' }
                    4       { 'Disabled' }
                    default { 'Unknown' }
                }

                $cscStatus = switch ($data.CSCStart.Start) {
                    1       { 'System' }
                    4       { 'Disabled' }
                    default { 'Unknown' }
                }

                Write-Debug "CSC=$cscStatus | CscService=$cscServiceStatus | Policy=$netCachePolicyStatus | Files=$($data.FileCount)"

                [PSCustomObject]@{
                    ComputerName     = $computer
                    NetCachePolicy   = $netCachePolicyStatus
                    CSCServiceStatus = $cscServiceStatus
                    CSCStatus        = $cscStatus
                    CacheActive      = if ($data.CacheInfo) { $data.CacheInfo.Active }   else { $false }
                    CacheEnabled     = if ($data.CacheInfo) { $data.CacheInfo.Enabled }  else { $false }
                    CacheLocation    = $data.CacheLocation
                    FileCount        = $data.FileCount
                    GroupPolicyName  = $data.GPOName
                    FileList         = if ($IncludeFileList) { $data.FileList } else { @() }
                    CollectionTime   = (Get-Date).ToString('dd-MM-yyyy HH:mm:ss')
                    Status           = 'Success'
                }
            }
            catch {
                Write-Error -Message "Failed to query '$computer': $($_.Exception.Message)" -ErrorAction Continue
                [PSCustomObject]@{
                    ComputerName   = $computer
                    Error          = $_.Exception.Message
                    Status         = 'Failed'
                    CollectionTime = (Get-Date).ToString('dd-MM-yyyy HH:mm:ss')
                }
            }
        }
    }
}