I am updating our 2013 environments to the October 2020 CU to patch a vulnerability reported by our security team. The last time we patched CUs in the production environment, the Upgrade-SPContent database portion took a really long time. We have 80+ content databases in one web application and about 60 in the other, so we wanted to split the load across several servers to decrease the upgrade time.

To remedy that, we updated our documentation to run the Upgrade command in parallel on up to 4 servers. The script I was planning on using is below, but I'm wondering if it will work as I expect it to across multiple servers. I'm trying to avoid hard coding database names into the script to make it easier to open and run on multiple servers.

Add-PSSnapin Microsoft.SharePOint.Powershell
$webapp = get-spwebapplication | Where-Object {$_.Url -like "*hnsc01*"} 
$collabs = Get-SPContentDatabase -WebApplication $webapp | Where-Object {$_.NeedsUpgrade -eq $true} | Sort-Object Name 

foreach($db in $collabs){
    Write-Host $("Upgrading content database: {0}" -f $db.Name) -ForegroundColor Yellow
    Upgrade-SPContentDatabase -Identity $db.Id -Confirm:$false 

My concern is that it will work fine on one server, but start to fail constantly on other servers as the initial Get-SPContentDatabase call "caches" the result in a point in time. I might be able to get around that by putting a second call in the foreach loop to check again if it needs updated.

Edit to include an updated script based on comments to make sure I'm understanding correctly:

$webapps = Get-SPWebApplication
foreach($webapp in $webapps){ 
    $dbs = Get-SPContentDatabase -WebApplication $webapp | Where-Object {$_.NeedsUpgrade -eq $true} | Sort-Object Name 
    foreach($db in $dbs){
        Write-Host $("Creating job to upgrade content database: {0}" -f $db.Name) -ForegroundColor Yellow
        Start-Job -Name $db.Name -ScriptBlock {Upgrade-SPContentDatabase -Identity $db.Id -Confirm:$false}

1 Answer 1


The issue isn't originating from the server the script is running on (the SharePoint server), but rather the time it takes to update the schema on the SQL server and the SQL server load.

If you want to parallel upgrades, use Start-Job instead of a foreach which will serialize the upgrades.

  • So something like Start-Job -ScriptBlock { Get-SPContentDatabase | ?{$_.NeedsUpgrade –eq $true} | Upgrade-SPContentDatabase -Confirm:$false} or foreach over all the databases and do a start-job on that? Commented Oct 27, 2020 at 14:47
  • Run a foreach across your databases with a Start-Job nested in the foreach passing in a specific database to your Upgrade-SPContentDatabase cmdlet. But again, the issue is due to the SQL portion, not the SharePoint server side. You'll likely want to serialize your upgrades to reduce the impact on SQL which will likely already be high during the upgrade process.
    – user6024
    Commented Oct 27, 2020 at 14:58
  • Ok that makes sense as far as the script is concerned. I guess I'm not versed enough to understand what it is actually doing. Do you have a link that may explain that? Commented Oct 30, 2020 at 13:08
  • What do you mean "It"? If by it you're referring to Upgrade-SPContentDatabase, SharePoint applies schema updates to the database which takes time and generates SQL load.
    – user6024
    Commented Oct 31, 2020 at 20:54
  • By it, I'm meaning the serialization aspect. I'm guessing this quickly iterates through all of the databases creating tasks on the SQL server and will upgrade as many in parallel as it can as resources are available instead of initiating an upgrade command and waiting for it to complete before going onto the next? Updated the post above to make sure I have it right. Commented Nov 2, 2020 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.