Apply Updates on Windows Nano Server 2016

In my previous post, List Updates on Windows Nano Server 2016, I talked about reporting the updates which are installed or missing from your Nano Servers. With that information in hand, you can now move to the more powerful aspect of actually patching them.

In my environment, I don’t want my hosts going out to Microsoft Update on their own, nor do I want to run an entire WSUS server just for a couple of Nano Servers so I patch them manually and this manual patching effort is something which will possibly resonate with others so I thought I would share it.

As it stands, the script requires you to fetch the updates yourself. I am going to work on something using Invoke-WebRequest in PowerShell to automate that step too, but that’s a small price to pay given the minimal number of updates Nano Server requires. Use the Microsoft Update Catalog at to obtain any updates you need. Something that was pointed out by Thomas Maurer in his Nano Server updates post at, there is an update for your Nano Servers which is not actually listed and this is the Servicing Stack Update for Windows 10 Version 1607, KB3176939 which you can download from This update is designed to be installed first and it improves the reliability and stability of the servicing stack in Windows which is used by the update process.

Applying Updates via PowerShell

Here is the script in question. I’m going to drop the script first and explain what’s happening at the end.

# Path to the Pre-Staged .msu Files from the Microsoft Update Catalog
$msuDirectory = "C:\NanoUpdates"
# KB Number for the Current Servicing Stack Update
$servicingStackKB = "kb3176936"
# Specify the SMB Share for the Nano Host Updates
$smbShare = "\\\NanoUpdates"

# List the Nano Hosts
$nanoHosts = "HOST1"

# Get the Credential for Managing the Nano Hosts
$cred = Get-Credential

$msuFiles = Get-ChildItem | Where-Object {($_.Name -like "*windows10.*") -and ($_.Extension -eq ".msu")}
$updateList = New-Object System.Collections.ArrayList

ForEach ($msuFile in $msuFiles) {
 $kbNumber = ($msuFile.Name).Split('-')[1]
 New-Item -ItemType Directory -Name $kbNumber -Force
 expand $msuFile.Name -F:* $kbNumber
 Move-Item -Path $kbNumber -Destination $smbShare\$kbNumber -Force

# Remove the Servicing Stack Update from the Update List
# This is to Ensure that we Can Target this Update to be Applied First Outside of the List

# Apply the Updates to the Host
ForEach ($nanoHost in $nanoHosts) {
 $session = New-PSSession -Credential $cred -ComputerName $nanoHost

 # Apply the Servicing Stack Update First
 Invoke-Command -Session $session -ScriptBlock {
 $servicingStackCAB = Get-ChildItem -Path $using:smbShare\$using:servicingStackKB\ | Where-Object {($_.Name -like "*windows10.*") -and ($_.Extension -eq ".cab")}
 Add-WindowsPackage -Online -PackagePath $servicingStackCAB.FullName -NoRestart

 # Test WinRM Port to Check for the Server Coming Back after the Restart
 Do {$connectResult = Test-NetConnection -CommonTCPPort WINRM -ComputerName $nanoHost -InformationLevel Quiet}
 Until ($connectResult = $true)

 # Apply the Remaining Windows Updates
 ForEach ($update in $updateList) {
 Invoke-Command -Session $session -ScriptBlock {
 $cabFile = Get-ChildItem -Path $using:smbShare\$using:update\ | Where-Object {($_.Name -like "*windows10.*") -and ($_.Extension -eq ".cab")}
 Add-WindowsPackage -Online -PackagePath $cabFile.FullName -NoRestart

 #Restart-Computer -Credential $cred -ComputerName $nanoHost
 Remove-PSSession $session

 Do {$connectResult = Test-NetConnection -CommonTCPPort WINRM -ComputerName $nanoHost -InformationLevel Quiet}
 Until ($connectResult = $true)
 Write-Host "Patching of $nanoHost has been completed." -ForegroundColor Green


Explaining the Script Operations

So here’s how this works. First, as already stated, you need to have the updates downloaded. There is a parameter declared for the path to that folder. The script will search for updates in that path and extract the .msu files to release the .cab files from them which is what we want for manually updating Nano Server. Once complete, the files are all copied over to an SMB share which you define on the network. Make sure this share is accessible to the Nano Servers.

Once this is done, using the $nanoHosts parameter or using the Active Directory group idea from the previous post, we connect to the hosts and first apply the servicing stack update. Once applied, the host gets restarted automatically and we use Test-NetConnection to query the WinRM service port to check for the host coming back up.

Once the host is back up, we re-connect to it and resume by applying all the remaining updates to the host with a second restart to complete the installation of the main wave of updates.

I have used this script already at home on my hosts and it’s working a treat.


Here’s a sidenote of interest. When I built my two physical Nano Server Hyper-V hosts, I built them using the PowerShell Cmdlets, before the Nano Image Generator tool was around and I opted to use Boot from VHD for them, creating a VHD file and configuring the Boot from VHD properties in WinPE as this would give me some servicing flexibility in the future.

The downside here is that the default image size for a Nano VHD is 4GB. Once the machine is running and doing it’s thing, I found that I could not apply KB3213986, the main cumulative update to my hosts because of insufficient space. I tried to use Resize-VHD to increase the VHD size but because it is in the boot partition, it wasn’t having it. In the end, I had to offline the hosts, load them into WinPE and increase the VHD size. I could of course have offline serviced them by building a new VHD which is of course, the reason I built them using Boot from VHD in the first place, but then I wouldn’t have been able to test this script would I.


Richard works as a Cloud Consultant for Fordway Solution where his primary focus is to help customers understand, adopt and develop with Microsoft Azure, Office 365 and System Center. Richard Green is an IT Pro with over 15 years' of experience in all things Microsoft including System Center and Office 365. He has previously worked as a System Center consultant and as an internal solutions architect across many verticals. Outside of work, he loves motorbikes and is part of the orange army, marshaling for NGRRC, British Superbikes and MotoGP. He is also an Assistant Cub Scout Leader.