Patching Windows: Part 3
I have a scheduled task that runs every Tuesday after 10 AM Pacific time to check for new updates. Historically, Microsoft posts its monthly patches between 10 AM and 11 AM on the second Tuesday of the month. This script computes if it's Patch Tuesday, or up to a week after Patch Tuesday, and only continues to run during that period of time.
My slow-as-hell-in-checking-for-updates LSTB machine won't find the May Cumulative Update until June, so I fetch and install it myself with 2ndtuesday.ps1:
[CmdletBinding()] Param( [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [DateTime] $Date = (Get-Date), [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [String] $Path = [System.IO.Path]::Combine(${Env:UserProfile}, 'Desktop'), [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [Version[]] $OSBuild = [Environment]::OSVersion.Version, [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [String] $Filter = 'x64', [Parameter(Mandatory=$False)] [Switch] $Force = $False, [Parameter(Mandatory=$False)] [Switch] $Fetch = $True ) $ErrorActionPreference = 'Stop' Set-StrictMode -Version 2 Import-Module -Force -Name ([System.IO.Path]::Combine($PSScriptRoot, 'WU.psm1')) Function Do-Start { Param() $tuesday = Get-SecondTuesday -DT $Date if (-not $Force) { if ( 8 -gt $Date.Day) { Return $False } if (15 -lt $Date.Day) { Return $False } if ($Date.Date -lt $tuesday.Date) { Return $False } if ($Date -ge $tuesday.AddDays(7)) { Return $False } } Write-Host ("Date: {0}" -f ($Date.ToLongDateString())) Write-Host ("Second Tuesday of month: {0}`n" -f ($tuesday.ToLongDateString())) Return $True } Function Do-End { Param( [Parameter(Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSObject[]] $Updates ) Write-Host "`nSSU updates: https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/ADV990001`n" foreach ($build in $OSBuild) { $build_str = Get-BuildString -Version $build $kb_obj = $Updates | Where-Object { $_.OSBuild -match $build_str } if ([String]::IsNullOrEmpty($kb_obj)) { Write-Error 'KB not found' } $release_date = Get-Date $kb_obj.ReleaseDate $source = Get-KBSource -Filter $Filter -KB $kb_obj.KB $uri = New-Object -TypeName System.Uri -ArgumentList $source.Source $kb_name = "{0:0000}-{1:00} Cumulative Update for Windows 10 Version {2} for {3}-based Systems ({4})" -f ($release_date.Year, $release_date.Month, $kb_obj.OSName, $Filter, $kb_obj.KB) # <URL:https://arstechnica.com/civis/viewtopic.php?t=1330043> $dst_path = '\\?\' + [System.IO.Path]::Combine($Path, $kb_name) $file_name = $uri.Segments[-1] $tmp_path = [System.IO.Path]::Combine(([System.IO.Path]::GetTempPath()), $file_name) mkdir $dst_path -ErrorAction SilentlyContinue | Out-Null if ($Fetch) { Start-BitsTransfer -Destination $tmp_path -Source $uri Move-Item -Verbose:$False -Force:$True -Path $tmp_path -Destination $dst_path Write-Host "Fetched:`n" } Write-Host ("OS Build: {0}`n" -f ($build)) Write-Host ("KB Name: `"{0}`"`n" -f ($kb_name)) Write-Host ("Uri: {0}" -f ($uri)) } Read-Host -Prompt "`nok?" Return } $count = 0 $global:LASTEXITCODE = 0 if (Do-Start) { do { $count++ try { $updates = Get-PublishedKBUpdates $updates | Format-Table -Property ReleaseDate,KB,OSBuild,OSName,SupportID,ReleaseWeek -AutoSize Do-End -Updates $updates Write-Host ("run: {0}, exitcode: {1}" -f ($count, $global:LASTEXITCODE)) } catch { Start-Sleep -Seconds 300 } } while (0 -ne $global:LASTEXITCODE) } # Start-Sleep -Seconds 10 # I like to read things before the window closes Exit # END
I don't mind fetching the .MSU file myself because I like to keep it around for my "Updates" folder, which I sometimes feed to a different script that builds a from-scratch Windows VM with an install ISO and can patch the base image for me with dism.exe.
Output looks a little like this:
PS C:\> .\2ndtuesday.ps1 -Fetch:$False Date: Tuesday, May 12, 2020 Second Tuesday of month: Tuesday, May 12, 2020 ReleaseDate KB OSBuild OSName SupportId ReleaseWeek ----------- -- ------- ------ --------- ----------- 2020-05-12 KB4556799 10.0.18363.836 1909 4529964 B 2020-05-12 KB4556799 10.0.18362.836 1903 4498140 B 2020-05-12 KB4551853 10.0.17763.1217 1809 4464619 B 2020-05-12 KB4556807 10.0.17134.1488 1803 4099479 B 2020-05-12 KB4556812 10.0.16299.1868 1709 4043454 B 2020-05-12 KB4556804 10.0.15063.2375 1703 4018124 B 2020-05-12 KB4556813 10.0.14393.3686 1607 4000825 B 2018-04-10 KB4093109 10.0.10586.1540 1511 4000824 B 2020-05-12 KB4556826 10.0.10240.18575 1507 4000823 B SSU updates: https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/ADV990001 OS Build: 10.0.17763.0 KB Name: "2020-05 Cumulative Update for Windows 10 Version 1809 for x64-based Systems (KB4551853)" Uri: http://download.windowsupdate.com/c/msdownload/update/software/secu/2020/05/windows10.0-kb4551853x64_ce1ea7def481ee2eb8bba6db49ddb42e45cba54f.msu ok?: run: 1, exitcode: 0
The URL for self-servicing updates is there because Microsoft doesn't make those easily accessible in a way DeploySharedLibrary can find. So far as I know you either (a) walk the Microsoft Update Catalog for a known SSU update for your precise build and look if it's been obsoleted, or (b) open a browser and go to the portal.msrc.microsoft.com link and click the link that's right for you. (b) is quick and you don't have to do it every single month. Every other month is fine. (Don't like it? Don't blame me. I voted for Kodos.)
This script puts a new directory on your Desktop called "YYYY-MM Cumulative Update for Windows 10 Version VVVV for FILTER-based Systems (KBXXXXXX)" and will store the update there. Change your architecture with -Filter as needed... but if you do you need to ask yourself why you're still on x86 or trying to act cool with ARM. I honestly have never tested this because I have one x86 machine and it's a tablet that I use as an e-reader and I leave it in airplane mode constantly.
No comments:
Post a Comment