Install Windows Server Servicing Stack Updates (SSU) using PowerShell

You can install Servicing Stack Updates (SSU) for Windows Server 2016 and Windows Server 2019 using PowerShell, without downtime. Because they must be installed prior to your normal Windows Server security updates, you can install them anytime you want to during the day. Here’s a small PowerShell example to do so.

Servicing the Windows servicing stack

Keeping the servicing stack updated is crucial for the security of your Windows-based infrastructure. Unfortunately, it’s also becoming more of a challenge. This post helps you installing Windows servicing stack updates prior to Windows Updates, using PowerShell, and streamlines your workflow a bit.

But first, what exactly are Servicing stack updates, or SSU’s? Microsoft writes:

Servicing stack updates provide fixes to the servicing stack, the component that installs Windows updates. Additionally, it contains the “component-based servicing stack” (CBS), which is a key underlying component for several elements of Windows deployment, such as DISM, SFC, changing Windows features or roles, and repairing components. The CBS is a small component that typically does not have updates released every month.

Servicing stack updatesMicrosoft Docs

Protip: I mentioned Windows Component-Based Servicing and CBS log files in my blog post with 5 ways to clean up files and free up disk space in Windows Server.

In my monthly Windows Updates routine, mostly using WSUS, I use the following PowerShell snippets to install Servicing Stack Updates manually in a loop.

First I approve all updates available and wait a moment for the updates to be downloaded to the WSUS client servers. In that moment of waiting, I write down the KB numbers for Server 2016 and Server 2019 Servicing Stack Updates (this month: KB4503537 for Server 2016 and KB4504369 for Server 2019.

Read this too:   IIS backup and restore

Protip: ever wondered why Windows Server Update Services (WSUS) offers Flash updates for Windows Server? Here is how to uninstall and remove Adobe Flash Player in Windows Server.

Next, my PowerShell script takes a KB number as input, and uses Get-ChildItem cmdlet to search for the update .cab file. If that file is found, it is installed using DISM.exe to install the SSU .cab file.

[CmdletBinding()]
	Param(
		[Parameter(Mandatory = $true, Position = 0, HelpMessage="Windows Server OS version (2019, 2016, 2012)")]
		[string]$serveros,
		[Parameter(Mandatory = $true, Position = 0, HelpMessage="Servicing Stack Update KB number")]
		[ValidateScript({
			if (!($_ -match "KB")) {
				Throw "[!!] the letters KB are missing"
			}
			else {
				$true
			}
		})]
		[string]$ssukb
	)

function install_SSU($servername, $kb) {
	invoke-command -computername $servername -scriptblock {
		$update = ((Get-ChildItem -Recurse C:\Windows\SoftwareDistribution\Download | Where-Object { $_.PSPath -like "*${using:kb}*" }) | Select-Object Name,DirectoryName)
		if(Test-Path("$($update.DirectoryName)\$($update.Name)")) {
			$process = Start-Process -NoNewWindow "c:\windows\system32\DISM.exe" -argument "/Online /Add-Package /PackagePath:$($update.DirectoryName)\$($update.Name)" -PassThru -Wait
			if($process.ExitCode -ne 0) {
				$a = "Installation process returned error code $($process.ExitCode) on ${Using:servername}"
				return $a
			}
			else {
				$a = "true, update {$Using:kb} instaled on ${Using:servername}"
				return $a
			}
		} else {
			$a = "$($update.DirectoryName)\$($update.Name) not found on ${Using:servername}"
			return $a
		}
	}
}

function restart_WindowsUpdate($servername, $os) {
	invoke-command -computername $servername -scriptblock {
		&net stop wuauserv
		&net start wuauserv
		if($os -eq "2019" -or $os -eq "2016") {
			Start-Process -NoNewWindow "c:\windows\system32\UsoClient.exe" -argument "startscan" -Wait	
			Start-Process -NoNewWindow "c:\windows\system32\UsoClient.exe" -argument "RefreshSettings" -Wait
		} else {
			Start-Process -NoNewWindow "c:\windows\system32\wuauclt.exe" -argument "/resetauthorization /DetectNow" -Wait
			Start-Process -NoNewWindow "c:\windows\system32\wuauclt.exe" -argument "/ReportNow" -Wait
		}
	}
}

if(($serveros -eq "2016") -or ($serveros -eq "2019")) {
	$serverversion = "Windows Server " + $serveros + "*"
	foreach($server in (Get-ADComputer -Filter "OperatingSystem -like '${serverversion}' -and enabled -eq '$true'").DNSHostName) {
		$b = install_SSU -servername "${server}" -kb "${ssukb}"
		$b
		restart_WindowsUpdate -server "${server}" -os "${serveros}"
	}
}

if($serveros -eq "2012") {
	foreach($server in (Get-ADComputer -Filter {(enabled -eq $True) -and (OperatingSystem -like "Windows Server 2012*")}).DNSHostName) {
		$b = install_SSU -servername "${server}" -kb "${ssukb}"
		$b
		restart_WindowsUpdate -server "${server}" -os "${serveros}"
	}
}

It may not be perfect but works for my situation. You can execute it for your Windows Server operating system versions like:

.\install-SSU.ps1 -serveros 2019 -ssukb KB4539571
.\install-SSU.ps1 -serveros 2016 -ssukb KB4540723
.\install-SSU.ps1 -serveros 2012 -ssukb KB4540725

The regular Windows Updates are installed using WSUS and PowerShell module PSWindowsUpdate. You can install this with NuGet:

Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Confirm:$false -Force
Install-Module -Name PSWindowsUpdate -Confirm:$false -Force

I have a Dutch article about PSWindowsUpdate at ITFAQ.nl.

Read this too:   5 Extra ways to clean up disk space in Windows Server
2,252 views

Leave a Reply

Your email address will not be published. Required fields are marked *