Replicating patch level from one server to another without WSUS/patch management

The scenario is: Server1 and Server2, both running Windows Server 2012 R2 at the same patch level, are currently in a load-balancing cluster. Server1 has application issues and advice is to replace it. It's been taken out of the cluster and Server3 is being provisioned as it's replacement.

When Server1 and Server2 were originally built no patch-management solution was used. They were built at the same time and just patched to the then-latest level.

The objective is to patch Server3 to the same level as Server2.

As mentioned, no patch-management solution is available.

Going through the updates on Server2 one-by-one and applying them to Server3 is, of course, an option, but we should be able to do something better than that. It is 2017, after all.

It is possible to retrieve a list of all updates on Server2 via PowerShell and by KB number, and this list is available.

But how to then download and apply these updates, and only these updates, to Server3?

Initial research has turned up a number of Windows update scripts, both VBS and PowerShell, but they all fail at the critical requirement that not all current updates must be applied.

Bringing Server2's patch level to current, then also the same for Server3, is also an option but one which I'd prefer to avoid owing to having to schedule downtime/maintenance windows (there being no viable Server1 in the cluster) then a bunch of application testing. Let's keep that as a last resort.

So - what are my reasonable options for automating this in a sensible way, given the above constraints?


Solution 1:

I'm pretty sure this is what you are looking for.

Run on server2 first to get your list of KB numbers, then run of server 3 and pass those KB numbers in.

Solution 2:

Cleaner probably to install WSUS. You can then use the WSUS powershell module to do this. This script looks at locally installed updates, connects to WSUS, then approves those updates for a specific group in WSUS:

$servername = <ip of WSUS>
$port       = "8530"
$groupname  = <name of server group>

# Import Libraries
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")

# Connect to WSUS
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($servername, $False, $port)

# Connect to local Update Service
$Session = New-Object -ComObject "Microsoft.Update.Session"
$Searcher = $Session.CreateUpdateSearcher()
$historyCount = $Searcher.GetTotalHistoryCount()
$installedUpdates = $Searcher.QueryHistory(0, $historyCount) | Select-Object Title

# Approve all locally installed updates in WSUS
foreach ($installedUpdate in $installedUpdates) {
  $update = $wsus.SearchUpdates($installedUpdate)
  $group = $wsus.GetComputerTargetGroups() | where {$_.Name -eq $groupname}
  $update[0].Approve(“Install”,$group)
}

You could also write all the local updates to a file:

$filename = <path>
$Session = New-Object -ComObject "Microsoft.Update.Session"
$Searcher = $Session.CreateUpdateSearcher()
$historyCount = $Searcher.GetTotalHistoryCount()
$installedUpdates = $Searcher.QueryHistory(0, $historyCount) | Select-Object Title
$installedUpdates | Export-Csv $filename

Then copy that file to the other server and run something like this: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387101(v=vs.85).aspx