Applying CU’s to SharePoint 2013 Servers with PowerShell

Here’s a very cool script that is a huge time saver for applying the cumulative updates to SharePoint.

To use it, just copy the code below into a text file and save that file as a .ps1 file. (e.g. C:\UpdateFolder\CUInstall.ps1)

05/07/2017 – When I originally wrote this post I had mentioned That I had no idea who wrote this code; but, I can tell you that I didn’t and that it works!  And, that is all still true except for the part about who wrote it. It was written by Russ Maxwell in 2013 – https://blogs.msdn.microsoft.com/russmax/2013/04/01/why-sharepoint-2013-cumulative-update-takes-5-hours-to-install/

Thanks Russ!

###########################
##Ensure Patch is Present##
###########################
$patchfile = Get-ChildItem | where{$_.Extension -eq ".exe"}
if($patchfile -eq $null)
{
Write-Host "Unable to retrieve the file. Exiting Script" -ForegroundColor Red
Return
}

########################
##Stop Search Services##
########################
##Checking Search services##
$srchctr = 1
$srch4srvctr = 1
$srch5srvctr = 1

$srv4 = get-service "OSearch15"
$srv5 = get-service "SPSearchHostController"

If(($srv4.status -eq "Running") -or ($srv5.status-eq "Running"))
{
Write-Host "Choose 1 to Pause Search Service Application" -ForegroundColor Cyan
Write-Host "Choose 2 to leave Search Service Application running" -ForegroundColor Cyan
$searchappresult = Read-Host "Press 1 or 2 and hit enter"
Write-Host

if($searchappresult -eq 1)
{
$srchctr = 2
Write-Host "Pausing the Search Service Application" -foregroundcolor yellow
Write-Host "This could take a few minutes" -ForegroundColor Yellow
$ssa = get-spenterprisesearchserviceapplication
$ssa.pause()
}

elseif($searchappresult -eq 2)
{
Write-Host "Continuing without pausing the Search Service Application"
}
else
{
Write-Host "Run the script again and choose option 1 or 2" -ForegroundColor Red
Write-Host "Exiting Script" -ForegroundColor Red
Return
}
}

Write-Host "Stopping Search Services if they are running" -foregroundcolor yellow
if($srv4.status -eq "Running")
{
$srch4srvctr = 2
set-service -Name "OSearch15" -startuptype Disabled
$srv4.stop()
}

if($srv5.status -eq "Running")
{
$srch5srvctr = 2
Set-service "SPSearchHostController" -startuptype Disabled
$srv5.stop()
}

do
{
$srv6 = get-service "SPSearchHostController"
if($srv6.status -eq "Stopped")
{
$yes = 1
}
Start-Sleep -seconds 10
}
until ($yes -eq 1)

Write-Host "Search Services are stopped" -foregroundcolor Green
Write-Host

#######################
##Stop Other Services##
#######################
Set-Service -Name "IISADMIN" -startuptype Disabled
Set-Service -Name "SPTimerV4" -startuptype Disabled
Write-Host "Gracefully stopping IIS W3WP Processes" -foregroundcolor yellow
Write-Host
iisreset -stop -noforce
Write-Host "Stopping Services" -foregroundcolor yellow
Write-Host

$srv2 = get-service "SPTimerV4"
if($srv2.status -eq "Running")
{$srv2.stop()}

Write-Host "Services are Stopped" -ForegroundColor Green
Write-Host
Write-Host

##################
##Start patching##
##################
Write-Host "Patching now keep this PowerShell window open" -ForegroundColor Magenta
Write-Host
$starttime = Get-Date

$filename = $patchfile.basename

Start-Process $filename

Start-Sleep -seconds 20
$proc = get-process $filename
$proc.WaitForExit()

$finishtime = get-date
Write-Host
Write-Host "Patch installation complete" -foregroundcolor green
Write-Host

##################
##Start Services##
##################
Write-Host "Starting Services Backup" -foregroundcolor yellow
Set-Service -Name "SPTimerV4" -startuptype Automatic
Set-Service -Name "IISADMIN" -startuptype Automatic

##Grabbing local server and starting services##
$servername = hostname
$server = get-spserver $servername

$srv2 = get-service "SPTimerV4"
$srv2.start()
$srv3 = get-service "IISADMIN"
$srv3.start()
$srv4 = get-service "OSearch15"
$srv5 = get-service "SPSearchHostController"

###Ensuring Search Services were stopped by script before Starting"
if($srch4srvctr -eq 2)
{
set-service -Name "OSearch15" -startuptype Automatic
$srv4.start()
}
if($srch5srvctr -eq 2)
{
Set-service "SPSearchHostController" -startuptype Automatic
$srv5.start()
}

###Resuming Search Service Application if paused###
if($srchctr -eq 2)
{
Write-Host "Resuming the Search Service Application" -foregroundcolor yellow
$ssa = get-spenterprisesearchserviceapplication
$ssa.resume()
}

Write-Host "Services are Started" -foregroundcolor green
Write-Host
Write-Host
Write-Host "Script Duration" -foregroundcolor yellow
Write-Host "Started: " $starttime -foregroundcolor yellow
Write-Host "Finished: " $finishtime -foregroundcolor yellow
Write-Host "Script Complete"

After you have the .ps1 file, save that .ps1 and the files you downloaded for the cu, usually a couple of uber files and an executable, into the same directory on your server. (e.g. c:\updateFolder)

If you don’t have the CU downloaded yet, here’s a link to TK’s blog – I recommend the November 2016 CU for SharePoint 2013; but, you’ll always want to check for any regressions and apply to a non-prod environment first.

Next, open PowerShell and navigate to the directory where you saved the .ps1 file, the CU exe file, and the other files (e.g. cd c:\updateFolder).

Make sure the Execution policy in PowerShell, is set to unrestricted (e.g. c:\updateFolder\Set-ExecutionPolicy unrestricted)

Call the .ps1 file (c:>\updateFolder\   .\CUInstall.ps1)

If prompted to allow, go ahead and allow all by pressing A, or Y

(If you have more servers in the farm, you should go to them and run the script, same options as this server)

When you run the PowerShell it will give you the option to stop search and other services, definitely pick this option.

Do not close the window, let it run until the script is completed.

VERY IMPORTANT:  At the end of the script if the patch requires a restart, do NOT restart, until the script has had an opportunity to restart the services and finish.

When prompted by the installer to restart, like so many other things in life, “Just Say No”

When the script finishes you’ll see Script Complete.

After the script completes go ahead and restart the server after all the servers in the farm have got to this point.

Run this script in parallel on other servers in the farm, obeying the same restart rules.

After all servers have received the CU, and restarted for good measure, and not before, go ahead and run psconfig either from the wizard or from Powershell, sequentially.

PSConfig.exe -cmd upgrade -inplace b2b -wait -cmd applicationcontent -install -cmd installfeatures -cmd secureresources -cmd services -install

One word of advice, I gleaned from reading posts by Stefan Gobner, if using the command line, err powershell, err psconfig.exe not psconfiggui.exe, make sure you use the above, as just running Psconfig.exe -cmd upgrade -inplace b2b -wait -force will not update the files in the _app_bin directory.  Something to keep in mind.  So, if you use the gui, then you don’t have to worry about those files getting updated because it triggers the Install-SPApplicationContent cmdlet.  Hope that helps.