SharepointConfigCacheReset.ps1

<#PSScriptInfo
 
.VERSION 1.18
 
.GUID 54b95d90-eac4-4598-88ad-8dbeee981a7b
 
.AUTHOR jan.tkac.sk@gmail.com
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS Sharepoint Config Cache Reset
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
1.0
    Added foreach loop to to all funcions to be able to use it with multiple servers.
1.1
    Added [string[]]$Servers parameter to be able to run the script for only one server.
    Added Write-Section function to visibly separate sections using write-host commandlet.
1.2
    Added [switch]TestOnly parameter to Start-SPTimerservice,Stop-SPTimerService,Remove-XMLFiles and Set-Cache_iniContnet functions.
1.4
    Added [switch]$ServerByServer parameter to the script.
    Changes in the main script block.
1.5
    Added and removed some empty lines in the host output.
1.6
    Added if($ServerByServer -and -not $TestOnly) condition.
1.7
    Added Write-FarmInfo function.
1.8
    Added a "-subsection" switch to the Write-Section function, removed Set-Content -Whatif line.
1.9
    Added write-subsection lines, edite text of some write-host lines in (-not $TestOnly -and $ServerByServer) condition.
1.10
    Script parameter "[string[]]$Servers" was changed to "$[string[]]$ServerList".
    In each function "$Servers" was changed to "$ComputerList".
    In each function "foreach ($Server in $Servers)" was changed to "foreach $(Computer in $ComputerList)".
    Main script slock Was adusted according to the changes above.
    Added Write-Host part in the Load-Sharepoint-Powershell function.
1.11
    Edited PSSCriptInfo
1.12
    Simplified versioning
1.13
    Changed The color scheme
1.18
    Metadata update
.PRIVATEDATA
 
#>


<#
 
.SYNOPSIS
    Reset configuration cache on all servers in the farm.
.DESCRIPTION
    For more info and screenshots go to:
        https://www.sysadmin-diary.com/sharepoint-config-cache-reset/
    Make sure to run the script with "-TestOnly" switch to test the script first without doing the actual reset.
    The script performs the following main steps:
        Searches for the configuration database GUID.
        Searches for the config cache folder based on the Database GUID.
        Stops the timer service.
        Removes XML files in the config cache folder.
        Sets the cache.ini content to 1.
        Starts the timer service.
    By default each main step is executed on all servers before the script goes to the next step.
    With "-ServerByServer" switch all main steps are executed on one server then another etc...
    You can use "-ServerList" switch to run the script only on specific servers, not the whole farm.
.Example
.\SharepointConfigCacheReset.ps1 -TestOnly
.Example
.\SharepointConfigCacheReset.ps1 -TestOnly -ServerByServer
.Example
.\SharepointConfigCacheReset.ps1 -TestOnly -ServerList Sever1,Server2
.Example
.\SharepointConfigCacheReset.ps1 -TestOnly -ServerList "Sever1","Server2" -ServerByServer
.Example
.\SharepointConfigCacheReset.ps1 -TestOnly -ServerList localhost
.Example
.\SharepointConfigCacheReset.ps1
.Example
.\SharepointConfigCacheReset.ps1 -ServerByServer
.Example
.\SharepointConfigCacheReset.ps1 -ServerList Sever1,Server2
.Example
.\SharepointConfigCacheReset.ps1 -ServerList "Sever1","Server2" -ServerByServer
.Example
.\SharepointConfigCacheReset.ps1 -ServerList localhost
 
#>
 
param(
    [switch]$TestOnly,
    [switch]$ServerByServer,
    [string[]]$ServerList
)

Function Write-Section($String,[switch]$SubSection){
    if($SubSection){
        Write-Host -ForegroundColor Yellow "`n".PadRight(120,".")
        Write-Host $String
        Write-Host -ForegroundColor Yellow "`n".PadLeft(120,".")
    }
    else{
        Write-Host -ForegroundColor Yellow -BackgroundColor DarkGray "`n`n".PadRight(120,"-")
        Write-Host $String
        Write-Host -ForegroundColor Yellow -BackgroundColor DarkGray "`n`n".PadLeft(120,"-")
    }
}
Function Load-SharePoint-Powershell
{
    If ((Get-PsSnapin |?{$_.Name -eq "Microsoft.SharePoint.PowerShell"})-eq $null)
    {
        Write-Section "Loading Sharepoint Powershell Snapin"
        Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction Stop
        if ($null -ne (Get-PsSnapin |?{$_.Name -eq "Microsoft.SharePoint.PowerShell"}))
        {
            Write-Host -ForegroundColor Green "The sharepoint powershell snapin has been imported. "
        }
    }
}
Load-SharePoint-Powershell
########################################Constants########################################
$SPfarm = Get-SPFarm 
$SPServers = $SPfarm.Servers | Where-Object {$_.Role -ne "invalid"} | Select-Object -ExpandProperty address
$ConfigDBGuid = Get-SPDatabase -Name $SPFarm.name | select -ExpandProperty id | select -ExpandProperty Guid
#$ConfigDBGuid = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\16.0\secure\ConfigDB' -Name 'Id' | select -ExpandProperty Id
$SecondsToWait = 2
$SPTimerServiceName = "SPTimerV4"
if ($ServerList -eq $null){$ServerList = $SPServers}
########################################Functions########################################

Function Write-FarmInfo(){
    Write-Host "Config DB Name: " -NoNewline
    Write-Host -ForegroundColor Yellow "$($SPfarm.Name)"

    Write-Host  "Config DB Guid: " -NoNewline
    Write-Host -ForegroundColor Yellow "$ConfigDBGuid`n"
    Start-Sleep $SecondsToWait

    Write-Host "Farm servers: "
    Write-Host -ForegroundColor Yellow "$($SPServers | out-string)"
    Start-Sleep $SecondsToWait
}

Function Test-RemoteWMIAccess($ComputerList=$ServerList)
{
    foreach ($Computer in $ComputerList)
    {
        Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
        Write-Host -ForegroundColor Yellow "Testing remote WMI connection to the timer service..." -nonewline
        try 
        {
            (Get-WmiObject -ComputerName $Computer Win32_Service -Filter "Name='$SPTimerServiceName'") | Out-Null
            Write-Host -ForegroundColor White -BackgroundColor DarkGreen "OK"
        }
        catch
        {
            Write-Host -ForegroundColor White -BackgroundColor DarkGreen "Failed"
            $TestFailed = $True
        }
        Start-Sleep $SecondsToWait
    }#foreach
    if ($TestFailed -eq $True)
    {
        return "TestFailed"
    }
}
Function Test-ConfigCacheFolders($ComputerList=$ServerList)
{
    Write-Host
    foreach ($Computer in $ComputerList)
    {
        Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
        Write-Host -ForegroundColor Yellow "Testing remote config cache folder access..."
        $ConfigCachePath = "\\$Computer\C$\ProgramData\Microsoft\SharePoint\Config\$ConfigDBGuid"
        Write-Host "$ConfigCachePath"
        If (Test-Path $ConfigCachePath)
        {
            Write-Host -ForegroundColor Green "This folder is accessible `n"
        } 
        else
        {                    
            Write-Host -ForegroundColor Red -BackgroundColor Yellow "This folder is not accessible `n"
            $TestFailed = $True
        }
        Start-Sleep $SecondsToWait

    }#Foreach
    if ($TestFailed -eq $True)
    {
        return "TestFailed"
    }
}
Function Check-Cache_iniContent($ComputerList)
{
    foreach($Computer in $ComputerList)
    {
        Write-Host -ForegroundColor Gray "[$Computer]" -nonewline
        Write-Host -ForegroundColor Yellow "Checking cache.ini content..."
        #$Cache_ini = Get-ChildItem $ConfigCacheFolder -Filter "*.ini"
        $Cache_ini = Get-Item "\\$Computer\C$\ProgramData\Microsoft\SharePoint\Config\$ConfigDBGuid\cache.ini"
        $Cache_iniContent = Get-Content $Cache_ini.FullName
        $LastWriteTime = $Cache_ini | select -ExpandProperty LastWriteTime
        Write-Host "$($ConfigCacheFolder.FullName)" -NoNewline
        Write-Host "$($Cache_ini.Name) content: " -NoNewline
        Write-Host -ForegroundColor Yellow "$Cache_iniContent" -NoNewline
        Write-Host " Last write time: " -NoNewline
        Write-Host -ForegroundColor Yellow "$LastWriteTime`n"
        Start-Sleep $SecondsToWait    
    }    
}
Function Check-XMLFiles($ComputerList)
{
    foreach($Computer in $ComputerList)
    {
        Write-Host -ForegroundColor Gray "[$Computer]" -nonewline
        Write-Host -ForegroundColor Yellow "Checking XML Files..."
        $ConfigCacheFolder = Get-Item \\$Computer\C$\ProgramData\Microsoft\SharePoint\Config\$ConfigDBGuid
        $XMLFiles = Get-ChildItem $ConfigCacheFolder -Filter "*.XML"
        $XMLcount = $XMLFiles.count
        if($XMLcount -gt 0)
        {
            $OldestXMLFile = $XMLFiles | Sort-Object -Descending CreationTime | select -ExpandProperty CreationTime -Last 1
        }
        else
        {
            $OldestXMLFile = "N/A"
        }
        Write-Host "XML file count: " -NoNewline
        Write-Host -ForegroundColor Yellow "$XMLcount" -NoNewline 
        Write-Host " Oldest XML file Date: " -NoNewline
        Write-Host -ForegroundColor Yellow "$OldestXMLFile`n"
        Start-Sleep $SecondsToWait   
    }
}
Function Stop-SPTimerService($ComputerList,[switch]$TestOnly)
{
    foreach($Computer in $ComputerList)
    {
        try
        {
            if($TestOnly)
            {
                Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
                Write-Host -ForegroundColor Blue -BackgroundColor Yellow "This is were $SPTimerServiceName would be stopped, checking the current status instead..."
                $Service = Get-WmiObject -ComputerName $Computer Win32_Service -Filter "Name='$SPTimerServiceName'"
                Write-Host -ForegroundColor Gray "$($Service.name) is currently $($Service.state)`n"
                Start-Sleep $SecondsToWait
            }
            else
            {
                Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
                Write-Host -ForegroundColor Red -BackgroundColor Yellow "Stopping the timer service..."
                (Get-WmiObject -ComputerName $Server Win32_Service -Filter "Name='$SPTimerServiceName'").StopService() | Out-Null
                Wait-TimerService -ComputerList $Computer -status "Stopped"
            }
        }
        catch
        {
            Write-Host "Unable to stop the timer service! The script will stop. Restart the timer services manually if needed!" -ForegroundColor Red -BackgroundColor Yellow
            $Error[0]
            exit
        }    
    }
}
Function Start-SPTimerService($ComputerList,[switch]$TestOnly)
{
    foreach($Computer in $ComputerList)
    {
        try
        {
            if($testonly)
            {
                Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
                Write-Host -ForegroundColor Blue -BackgroundColor Yellow "This is were $SPTimerServiceName would be started, checking the current status instead..."
                $Service = Get-WmiObject -ComputerName $Computer Win32_Service -Filter "Name='$SPTimerServiceName'"
                Write-Host -ForegroundColor Gray "$($Service.name) is currently $($Service.state)`n"
                Start-Sleep $SecondsToWait
            }
            else
            {
                Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
                Write-Host -ForegroundColor Red -BackgroundColor Yellow "Starting $SPTimerServiceName service..."
                (Get-WmiObject -ComputerName $Server Win32_Service -Filter "Name='$SPTimerServiceName'").StartService() | Out-Null
                Start-Sleep $SecondsToWait
                Wait-TimerService -ComputerList $Computer -status "Running"
            }
        }
        catch
        {
            Write-Host "Unable to start the timer service!" -ForegroundColor Red -BackgroundColor Yellow
        }    
    }
}
Function Wait-TimerService($ComputerList,$Status)
{
    foreach($Computer in $ComputerList)
    {
        While((Get-WmiObject -ComputerName $Computer Win32_Service -Filter "Name='$SPTimerServiceName'").State -ne $Status)
        {
            Write-Host -ForegroundColor Yellow "Waiting for $SPTimerServiceName..." 
            Start-Sleep 1
        }
        Write-Host -ForegroundColor Green "$SPTimerServiceName is $Status.`n"
        Start-Sleep $SecondsToWait     
    }
}
Function Remove-XMLFiles($ComputerList,[switch]$TestOnly) 
{
    foreach($Computer in $ComputerList)
    {
        if($TestOnly)
        {
            Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
            Write-Host -ForegroundColor Blue -BackgroundColor Yellow "This is where the XML files would be removed...`n"
            $ConfigCacheFolder = Get-Item \\$Computer\C$\ProgramData\Microsoft\SharePoint\Config\$ConfigDBGuid
            $XMLFiles = Get-ChildItem $ConfigCacheFolder -Filter "*.XML"
        }
        else{
            Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
            Write-Host -ForegroundColor Red -BackgroundColor Yellow "Removing XML Files...`n"
            $ConfigCacheFolder = Get-Item \\$Computer\C$\ProgramData\Microsoft\SharePoint\Config\$ConfigDBGuid
            $XMLFiles = Get-ChildItem $ConfigCacheFolder -Filter "*.XML"
            $XMLFiles | Remove-Item
            }
        Start-Sleep $SecondsToWait    
    }
}
Function Set-Cache_iniContent($ComputerList,[switch]$TestOnly)
{
    foreach($Computer in $ComputerList)
    {
        $Cache_ini = Get-Item "\\$Computer\C$\ProgramData\Microsoft\SharePoint\Config\$ConfigDBGuid\cache.ini"
        if ($TestOnly)
        {
            Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
            Write-Host -ForegroundColor Blue -BackgroundColor Yellow "This is where cache.ini content would be set to 1...`n"
        }
        else
        {
            Write-Host -ForegroundColor Gray "[$Computer]" -NoNewline
            Write-Host -ForegroundColor Red -BackgroundColor Yellow "Setting cache.ini content to 1...`n"
            Set-Content -Path $Cache_ini -Value "1"
        }
        Start-Sleep $SecondsToWait    
    }
}
########################################MainScriptBlock########################################

Write-Section "Basic Farm Information - Test Only"
Write-FarmInfo

if($TestOnly -and -not $ServerByServer ){
    Write-Section "Testing remote WMI connection to the timer service - Test Only"
    if ((Test-RemoteWMIAccess) -eq "TestFailed")
    {
        Write-Host -ForegroundColor Yellow "`nCould not connect to the timer service via remote WMI on at least one of the servers. You need to fix this issue."
        continue
    }
    Write-Section "Checking if the remote cache folders are accessible - Test Only"
    if ((Test-ConfigCacheFolders) -eq "TestFailed")
    {
        Write-Host -ForegroundColor Yellow "`nNot all config folders are accessible, cannot perform the cache reset on all servers. You need to fix this issue."
        continue
    }
    Write-Section "Stopping the Timer services - Test Only"
    foreach ($Server in $ServerList)
    {
        Stop-SPTimerService -ComputerList $Server -TestOnly
    }
    Write-Section "Removing XML files - Test Only"
    foreach ($Server in $ServerList)
    {
        Check-XMLFiles -ComputerList $Server
        Remove-XMLFiles -ComputerList $Server -TestOnly
        Check-XMLFiles -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    Write-Section "Setting cache.ini file content to 1 - Test Only"
    foreach ($Server in $ServerList)
    {
        Check-Cache_iniContent -ComputerList $Server
        Set-Cache_iniContent -ComputerList $Server -TestOnly
        Check-Cache_iniContent -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    Write-Section "Starting the timer services - Test Only" -BackgroundColor DarkBlue -ForegroundColor Yellow
    foreach ($Server in $ServerList)
    { 
        Start-SPTimerService -ComputerList $Server -TestOnly
    }
    Write-Section "Checking the XML count and cache.ini content - Test Only"
    foreach ($Server in $ServerList)
    {
        Check-XMLFiles -ComputerList $Server
        Check-Cache_iniContent -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    
}

elseif($TestOnly -and $ServerByServer){

    foreach ($Server in $ServerList)
    {
        Write-Section "Resetting config cache on $Server - Test Only."
        Write-Section "Testing WMI connection and Cache folder access - Test Only." -SubSection
        Test-RemoteWMIAccess -ComputerList $Server
        Test-ConfigCacheFolders -ComputerList $Server
        Write-Section "Stopping the timer service - Test Only." -SubSection
        Stop-SPTimerService -ComputerList $Server -TestOnly
        Write-Section "Removing and checking XML files - Test Only." -SubSection
        Check-XMLFiles -ComputerList $Server
        Remove-XMLFiles -ComputerList $Server -TestOnly
        Check-XMLFiles -ComputerList $Server
        Write-Section "Setting and checking cache.ini file content - Test Only." -SubSection
        Check-Cache_iniContent -ComputerList $Server
        Set-Cache_iniContent -ComputerList $Server -TestOnly
        Check-Cache_iniContent -ComputerList $Server
        Write-Section "Starting the timer service - Test Only." -SubSection
        Start-SPTimerService -ComputerList $Server -TestOnly
        Write-Section "Checking XML files and cache.ini content again - Test Only." -SubSection
        Check-XMLFiles -ComputerList $Server
        Check-Cache_iniContent -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }

stopping
}


elseif(-not $TestOnly -and -not $ServerByServer ){
    Write-Section "Testing remote WMI connection to the timer service"
    if ((Test-RemoteWMIAccess) -eq "TestFailed")
    {
        Write-Host -ForegroundColor Yellow "`nCould not connect to the timer service via remote WMI on at least one of the servers. You need to fix this issue."
        continue
    }
    Write-Section "Checking if the remote cache folders are accessible..."
    if ((Test-ConfigCacheFolders) -eq "TestFailed")
    {
        Write-Host -ForegroundColor Yellow "`nNot all config folders are accessible, cannot perform the cache reset on all servers. You need to fix this issue."
        continue
    }
    Write-Section "Stopping the Timer services..."
    foreach ($Server in $ServerList)
    {
        Stop-SPTimerService -ComputerList $Server
    }
    Write-Section "Removing XML files..."
    foreach ($Server in $ServerList)
    {
        Check-XMLFiles -ComputerList $Server
        Remove-XMLFiles -ComputerList $Server
        Check-XMLFiles -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    Write-Section "Setting cache.ini file content to 1..."
    foreach ($Server in $ServerList)
    {
        Check-Cache_iniContent -ComputerList $Server
        Set-Cache_iniContent -ComputerList $Server
        Check-Cache_iniContent -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    Write-Section "Starting the timer services..." -BackgroundColor DarkBlue -ForegroundColor Yellow
    foreach ($Server in $ServerList)
    { 
        Start-SPTimerService -ComputerList $Server
    }
    Write-Section "Checking the XML count and cache.ini content..."
    foreach ($Server in $ServerList)
    {
        Check-XMLFiles -ComputerList $Server
        Check-Cache_iniContent -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    
}

elseif (-not $TestOnly -and $ServerByServer){
    foreach ($Server in $ServerList)
    {
        Write-Section "Resetting config cache on $Server"
        Write-Section "Testing WMI connection and Cache folder access." -SubSection
        Test-RemoteWMIAccess -ComputerList $Server
        Test-ConfigCacheFolders -ComputerList $Server
        Write-Section "Stopping the timer service." -SubSection
        Stop-SPTimerService -ComputerList $Server
        Write-Section "Removing and checking XML files." -SubSection
        Check-XMLFiles -ComputerList $Server
        Remove-XMLFiles -ComputerList $Server
        Check-XMLFiles -ComputerList $Server
        Write-Section "Setting and checking cache.ini file content." -SubSection
        Check-Cache_iniContent -ComputerList $Server
        Set-Cache_iniContent -ComputerList $Server
        Check-Cache_iniContent -ComputerList $Server
        Write-Section "Starting the timer service." -SubSection
        Start-SPTimerService -ComputerList $Server
        Write-Section "Checking XML files and cache.ini content again." -SubSection
        Check-XMLFiles -ComputerList $Server
        Check-Cache_iniContent -ComputerList $Server
        Write-Host "`n".PadLeft(80,".")
    }
    
}