Upgrade SharePoint 2013 after installing Patches or CU

I wrote this script to provide several options that have helped me successfully run PSConfig upgrades.

This script will do the following:

  • Start IIS in case it is stopped (could be stopped while installing patches)
  • Run any pending admin service jobs
  • Clear the local configuration cache
  • Provide a menu of 3 options for upgrade:
    • Simple
    • Advanced
    • Stuck at 10% progress during a previous run
  • Initialize Resource Security
Here is the PowerShell script:


#region INFO

########################
####   INFORMATION   ###
########################

<# 
.SYNOPSIS
    This script will attempt to run good actions to ensure the successful upgrade of SharePoint.
.DESCRIPTION 
    Uses the PSConfig.exe application
.EXAMPLE 
    .\Upgrade_PSConfig_PatchLevel.ps1
.LINK 
    Open this link for any issues observed during the upgrade as reported in the logs:
    https://technet.microsoft.com/en-us/library/cc262967(v=office.15)
.NOTES 
    File Name :  
    Author    : Eric Jochens 
    Tags      : sharepoint, upgrade
#>

#endregion



#region FUNCTIONS

#######################
####   FUNCTIONS   ####
#######################


function ChoiceMenu-Upgrade
<# 
.SYNOPSIS 
    This will implement a popup menu for choices you give the operator.
.EXAMPLE
    ChoiceMenu-Upgrade
#>
{
Begin
{
        #Title bar of popup:
        $title   = "Upgrade SharePoint"
        
        #Question displayed above choices:
        $message = "What type of upgrade process do you want to run?"
}
Process
{
        #Choices:
        $simple    = New-Object System.Management.Automation.Host.ChoiceDescription "&Simple", "PSConfig.exe -cmd upgrade -inplace b2b -force"
        $advanced  = New-Object System.Management.Automation.Host.ChoiceDescription "&Advanced", "PSConfig.exe -cmd upgrade -inplace b2b -force -cmd applicationcontent -install -cmd installfeatures"
        $10Percent = New-Object System.Management.Automation.Host.ChoiceDescription "&10Percent", "Run if the process got stuck at 10% before."
        $cancel    = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel", "This will cancel the prompt and not run any actions."

        #Settings:
        $options  = [System.Management.Automation.Host.ChoiceDescription[]]($simple,$advanced,$10Percent)
        $result   = $host.ui.PromptForChoice($title, $message, $options, 0)
    }
    End
{
        Return $result
    }
}

function ChoiceMenu-Upgrade2013Workflow
<# 
.SYNOPSIS 
    This will implement a popup menu for choices you give the operator.
.EXAMPLE
    ChoiceMenu-Upgrade2013Workflow
#>
{    
Begin
{
        #Title bar of popup:
        $title   = "Workflow 2013 Upgrade"

        #Question displayed above choices:
        $message = "Is the 2013 Workflow system installed on this farm?"
}
Process
{
        #Choices:
        $yes      = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Upgrade the 2013 workflow activities"
        $no       = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Ignore 2013 workflow as it is not installed"
        
        #Settings:
        $options  = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no)
        $result   = $host.ui.PromptForChoice($title, $message, $options, 0)
    }
    End
{
        Switch ($result)
        {
            0
            {
                Write-Host "Initiating the 2013 Workflow upgrade procedure." -f Cyan
                #(To copy workflow activities installed on the SharePoint host to an instance of the Workflow Service)
                #get the Workflow Service Address:
                $wfProxy = Get-SPWorkflowServiceApplicationProxy
                $wfURL   = $wfProxy.GetWorkflowServiceAddress((Get-SPSite -Limit 1 -WarningAction SilentlyContinue))
                #Copy the activities:
                $cred  = [System.Net.CredentialCache]::DefaultNetworkCredentials
                Copy-SPActivitiesToWorkflowService -WorkflowServiceAddress $wfURL -Credential $cred -Force $true
            }
        1
            {
                Write-Host "Skipping the 2013 Workflow upgrade procedure." -f Cyan
            }
        }
    }


Function Clear-SharePoint-ConfigurationCache-LocalServer
<# 
.SYNOPSIS 
    This function will clear the configuration cache on the current SharePoint server.
.DESCRIPTION 
    This will:
        (1) Stop the timer service
        (2) Delete all the xml files in the configuration cache folder
        (3) Change the count in the cache.ini file to 1
        (4) Start the SharePoint Timer Service
        (5) Report that the xml files have been rebuilt
.EXAMPLE
    Clear-SharePoint-ConfigurationCache-LocalServer
#>
{    
Begin
{
    $StartTime = Get-Date
    Write-Host "Start Time:" $StartTime
    $DateStr = $StartTime.ToString("yyyy-MM-dd_HHmm")
        
        Write-Host "Clear the SharePoint Configuration Cache on this server" -f Cyan
        Write-Host "Stopping the SharePoint Timer Service" -f Cyan

        $timerV4 = Get-Service -Name SPTimerV4
        If($timerV4.Status -ne "Stopped")
        {
            Stop-Service $timerV4
        }
        Start-Sleep -Seconds 2
        If($timerV4.Status -eq "Stopped")
        {
            Write-Host "SharePoint Timer Service is stopped" -f Green
        }

}
Process
{
        $configDB = Get-SPDatabase | ?{$_.Type -eq "Configuration Database"}
        [String]$confidDbId = $configDB.Id.Guid

        $cacheDirectory = Get-ChildItem -Path "c:\ProgramData\Microsoft\SharePoint\Config" -Filter $confidDbId

        $cacheIni = Get-ChildItem -Path $cacheDirectory.FullName -Recurse -Include "cache.ini"
        [Int]$cacheIniCountStart = Get-Content -Path $cacheIni.FullName
        Write-Host "cache.ini integer content in Configuration Cache folder is:" $cacheIniCountStart

        [Array]$xmlFiles = @()
        [Array]$xmlFiles = Get-ChildItem -Path $cacheDirectory.FullName -Recurse -Include "*.xml"
        [Int]$xmlActualFileCountStart = $xmlFiles.Count
        Write-Host "xml file  count in Configuration Cache folder is:" $xmlActualFileCountStart

        [Array]$xmlFiles = @()
        [Array]$xmlFiles = Get-ChildItem -Path $cacheDirectory.FullName -Recurse -Include "*.xml"

        While($xmlFiles.Count -ne 0)
        {
            Write-Host "Deleting" $xmlFiles.Count "xml files..." -f Cyan

            ForEach($xmlFile in $xmlFiles)
            {
                Remove-Item -Path $xmlFile.FullName -Force
            }
            [Array]$xmlFiles = @()
            [Array]$xmlFiles = Get-ChildItem -Path $cacheDirectory.FullName -Recurse -Include "*.xml"
        }

        Clear-Content -Path $cacheIni.FullName
        While((Get-Content -Path $cacheIni.FullName) -ne 1)
        {
            Write-Host "Setting cache.ini contents to 1" -f Cyan
            Set-Content -Path $cacheIni.FullName -Value "1"
        }
    }
    End
{
        Write-Host "Starting the SharePoint Timer Service" -f Cyan
        $timerV4 = Get-Service -Name SPTimerV4
        If($timerV4.Status -ne "Running")
        {
            Start-Service $timerV4
        }
        While($timerV4.Status -ne "Running")
        {
            Write-Host "Timer Service is:" (Get-Service -Name SPTimerV4).Status
            Start-Sleep -Seconds 3
        }
        If((Get-Service -Name SPTimerV4).Status -eq "Running")
        {
            Write-Host "SharePoint Timer Service is running" -f Green
        }

        #Wait for the XML file count to be correct
        [Int]$timeElapsed = 0
        Write-Host "Waiting for the xml file count to reach the right count..."
        While((Get-ChildItem -Path $cacheDirectory.FullName -Recurse -Include "*.xml").Count -ne $xmlActualFileCountStart)
        {
            Write-Host "Time-Elapsed:" $timeElapsed "seconds"
            Start-Sleep -Seconds 5
            $timeElapsed = $timeElapsed + 5
        }
        Start-Sleep -Seconds 3

        #test to see that xml file count and the contents of cache.ini are what we started with:
        [Int]$cacheIniCountEnd = Get-Content -Path $cacheIni.FullName
        [Array]$xmlFiles = @()
        [Array]$xmlFiles = Get-ChildItem -Path $cacheDirectory.FullName -Recurse -Include "*.xml"
        [Int]$xmlActualFileCountEnd = $xmlFiles.Count

        If($cacheIniCountEnd -eq $cacheIniCountStart)
        {
            Write-Host "cache.ini has the same number!" -f Green
        }
        Else
        {
            Write-Host "cache.ini has changed!" -f White -b Red
            Write-Host "cache.ini start      :" $cacheIniCountStart
            Write-Host "cache.ini end        :" $cacheIniCountEnd
        }

        If($xmlActualFileCountEnd -eq $xmlActualFileCountStart)
        {
            Write-Host "XML files are the right count!" -f Green
        }
        Else
        {
            Write-Host "XML file count has a different count!" -f Red
            Write-Host "XML file count start:" $xmlActualFileCountStart
            Write-Host "XML file count end  :" $xmlActualFileCountEnd
        }

    $EndTime = Get-Date
    $TimeToComplete = $EndTime - $StartTime
    Write-Host ("Script Complete")
    Write-Host ("End Time       : " + $EndTime)
    Write-Host ("Total Elapsed  : " + $TimeToComplete.Minutes + " min " + $TimeToComplete.Seconds + " sec")
        [System.GC]::Collect()

    }#end
}#function


#endregion


#region SCRIPT

####################
#####  Script  #####
####################

#System Variables
$StartTime = Get-Date
Set-Location -Path "C:\"
Clear-Host
Write-Host "Start Time:     " $StartTime
$DateStr = $StartTime.ToString("yyyy-MM-dd_HHmm")
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA 0

Get-SPProduct | Format-Table -Autosize

$wwwService = Get-Service "W3SVC"
If($wwwService.Status -ne "Running")
{
    $wwwService.start()
}
Else
{
    Write-Host "The IIS service is running" -f Green
}


Write-Host "This next section can fail and that is okay, it will try to run any stalled admin jobs" -f Green
net stop SPTimerV4
Start-SPAdminJob -Verbose
net start SPTimerV4

#Clear and rebuild the local configuration cache as this can cause issues with upgrades
Clear-SharePoint-ConfigurationCache-LocalServer

#initiate the function to open a menu and choose the upgrade script to run:
$choiceUpgrade = ChoiceMenu-Upgrade

Switch ($choiceUpgrade)
{
0
    {
        Write-Host $title ": Running the Simple upgrade process." -f Cyan
        PSConfig.exe -cmd upgrade -inplace b2b -force
        ChoiceMenu-Upgrade2013Workflow
    }
1
    {
        Write-Host $title ": Running the Advanced upgrade process." -f Cyan
        PSConfig.exe -cmd upgrade -inplace b2b -force -cmd applicationcontent -install -cmd installfeatures
        ChoiceMenu-Upgrade2013Workflow
    }
2
    {
        Write-Host $title ": Running the Stuck at 10% upgrade process." -f Cyan
        PSConfig -cmd upgrade -inplace b2b -wait -cmd applicationcontent -install -cmd installfeatures -cmd secureresources
        # -WAIT = No timer job so the upgrade happens in real time in the psconfig process.
        # -FORCE = Removes all existing upgrade jobs incase a timer job is stuck.
        ChoiceMenu-Upgrade2013Workflow
    }
3
    {
        Write-Host $title ": Canceled." -f DarkYellow
    }
}#switch

#this was added for a farm to fix an issue where the Managed Metadata service was no longer connected to the site collection.
Initialize-SPResourceSecurity

$EndTime = Get-Date
$TimeToComplete = $EndTime - $StartTime
Write-Host -Message ("Script Complete.")
Write-Host -Message ("End Time     : " + $EndTime)
Write-Host -Message ("Total Elapsed: " + $TimeToComplete.Minutes + " min " + $TimeToComplete.Seconds + " sec")

#endregion

Comments

Popular posts from this blog

SharePoint Designer 2013 Approval Workflow with Comments

SharePoint Search - Content Processing Pipeline Failed to Process the Item

Change SharePoint server hostname and Web Application Names