Public/Get-OSBUpdate.ps1
<# .SYNOPSIS Manage OSBuilder Catalogs and Microsoft Updates .DESCRIPTION Function used by OSBuilder to update Catalogs and to download Microsoft Updates. Content is saved to OSBuilder\Content\Updates .LINK https://www.osdeploy.com/osbuilder/docs/functions/updates/get-osbupdate .PARAMETER Catalog Selects the Catalog JSON file containing the Updates .PARAMETER Download Executes the Download of files .PARAMETER HideDetails Hides all results .PARAMETER IseGridView Displays the Updates in a PowerShell GridView so Updates can be selected. .PARAMETER RemoveSuperseded Removes Downloaded Updated that have been Superseded .PARAMETER ShowDownloaded Lists Downloaded Updates .PARAMETER UpdateCatalogs Downloads updated Catalogs from GitHub .EXAMPLE Get-OSBUpdate -Catalog Cumulative -Download Downloads all Cumulative Updates for Windows 10 and Windows Server 2016 .EXAMPLE Get-OSBUpdate -Catalog Adobe -FilterOS 'Windows 10' -FilterOSArch 'x64' -FilterOSBuild '1803' Lists all Adobe Security Updates for Windows 10 x64 1803 .EXAMPLE Get-OSBUpdate -Catalog Adobe -Download -FilterOS 'Windows 10' -FilterOSArch 'x64' -FilterOSBuild '1803' Downloads all Adobe Security Updates for Windows 10 x64 1803 #> function Get-OSBUpdate { [CmdletBinding()] PARAM ( [ValidateSet('Custom','Adobe','Component','Cumulative','DotNet','FeatureOnDemand','LanguagePack','LanguageInterfacePack','LanguageFeature','Servicing','Setup','Windows 7 x64 7601','Windows 7 x86 7601')] [string]$Catalog, [switch]$Download, [string]$FilterCategory, [string]$FilterKBNumber, [string]$FilterKBTitle, [ValidateSet('ar-SA','bg-BG','zh-CN','zh-TW','hr-HR','cs-CZ','da-DK','nl-NL','en-US','en-GB','et-EE','fi-FI','fr-CA','fr-FR','de-DE','el-GR','he-IL','hu-HU','it-IT','ja-JP','ko-KR','lv-LV','lt-LT','nb-NO','pl-PL','pt-BR','pt-PT','ro-RO','ru-RU','sr-Latn-RS','sk-SK','sl-SI','es-MX','es-ES','sv-SE','th-TH','tr-TR','uk-UA')] [string]$FilterLP, [ValidateSet('af-ZA','am-ET','as-IN','az-Latn-AZ','be-BY','bn-BD','bn-IN','bs-Latn-BA','ca-ES','ca-ES-valencia','chr-CHER-US','cy-GB','eu-ES','fa-IR','fil-PH','ga-IE','gd-GB','gl-ES','gu-IN','ha-Latn-NG','hi-IN','hy-AM','id-ID','ig-NG','is-IS','ka-GE','kk-KZ','km-KH','kn-IN','kok-IN','ku-ARAB-IQ','ky-KG','lb-LU','lo-LA','mi-NZ','mk-MK','ml-IN','mn-MN','mr-IN','ms-MY','mt-MT','ne-NP','nn-NO','nso-ZA','or-IN','pa-Arab-PK','pa-IN','prs-AF','quc-Latn-GT','quz-PE','rw-RW','sd-Arab-PK','si-LK','sq-AL','sr-Cyrl-BA','sr-Cyrl-RS','sw-KE','ta-IN','te-IN','tg-Cyrl-TJ','ti-ET','tk-TM','tn-ZA','tt-RU','ug-CN','ur-PK','uz-Latn-UZ','vi-VN','wo-SN','xh-ZA','yo-NG','zu-ZA')] [string]$FilterLIP, [ValidateSet('Windows 10','Windows Server 2016','Windows Server 2019','Windows 7')] [string]$FilterOS, [ValidateSet('x64','x86')] [string]$FilterOSArch, [ValidateSet('1507','1511','1607','1703','1709','1803','1809')] [string]$FilterOSBuild, [switch]$HideDetails, #[switch]$HideOptionalUpdates, [switch]$IseGridView, [switch]$RemoveSuperseded, [switch]$ShowDownloaded, [switch]$UpdateCatalogs ) BEGIN { #Write-Host '========================================================================================' -ForegroundColor DarkGray #Write-Host "$($MyInvocation.MyCommand.Name) BEGIN" -ForegroundColor Green #=================================================================================================== Write-Verbose '19.1.1 Initialize OSBuilder' #=================================================================================================== Get-OSBuilder -CreatePaths -HideDetails } PROCESS { Write-Host '========================================================================================' -ForegroundColor DarkGray Write-Host "$($MyInvocation.MyCommand.Name) PROCESS" -ForegroundColor Green #=================================================================================================== Write-Verbose '19.1.1 Reset Variables' #=================================================================================================== $null = $ImportCatalog $CatalogDownloads = @() $DownloadedUpdates = @() $SupersededUpdates = @() #=================================================================================================== Write-Verbose '19.1.1 Get Catalogs' #=================================================================================================== if (!(Test-Path "$CatalogLocal")) {$UpdateCatalogs = $true} if (Test-Path "$OSBuilderContent\Updates\Catalog.json") { Remove-Item "$OSBuilderContent\Updates\Catalog.json" -Force | Out-Null $UpdateCatalogs = $true } if (Test-Path "$OSBuilderContent\Updates\Catalog.xml") { Remove-Item "$OSBuilderContent\Updates\Catalog.xml" -Force | Out-Null $UpdateCatalogs = $true } #=================================================================================================== Write-Verbose '19.1.1 Update Catalogs' #=================================================================================================== if ($UpdateCatalogs.IsPresent) { Write-Warning "Downloading $OSBuilderCatalogURL" $statuscode = try {(Invoke-WebRequest -Uri $OSBuilderCatalogURL -UseBasicParsing -DisableKeepAlive).StatusCode} catch [Net.WebException]{[int]$_.Exception.Response.StatusCode} if (!($statuscode -eq "200")) { Write-Warning "Could not connect to $OSBuilderCatalogURL (Status Code: $statuscode) ..." } else { Invoke-WebRequest -Uri "$OSBuilderCatalogURL" -OutFile "$CatalogLocal" if (Test-Path "$CatalogLocal") { $CatalogJson = Get-Content -Path "$CatalogLocal" | ConvertFrom-Json foreach ($item in $($CatalogJson.Catalogs)) { if (!(Test-Path "$OSBuilderContent\Updates\$($item.Catalog)")){ New-Item "$OSBuilderContent\Updates\$($item.Catalog)" -ItemType Directory -Force | Out-Null } $statuscode = try {(Invoke-WebRequest -Uri $OSBuilderCatalogURL -UseBasicParsing -DisableKeepAlive).StatusCode} catch [Net.WebException]{[int]$_.Exception.Response.StatusCode} if ($statuscode -eq "200") { Invoke-WebRequest -Uri "$($item.Url)" -OutFile "$OSBuilderContent\Updates\$($item.Catalog)\$(Split-Path "$($item.Url)" -Leaf)" } } } } } #=================================================================================================== Write-Verbose '19.1.1 Catalog Test' #=================================================================================================== if (!(Test-Path "$CatalogLocal")) { Write-Warning "$CatalogLocal could not be downloaded ... Exiting" Return } #=================================================================================================== Write-Verbose '19.1.1 Get Update Catalogs' #=================================================================================================== if ($Catalog) { if (!(Test-Path "$OSBuilderContent\Updates\$Catalog")) {New-Item "$OSBuilderContent\Updates\$Catalog" -ItemType Directory -Force | Out-Null} $CatalogsXmls = Get-ChildItem "$OSBuilderContent\Updates\$Catalog" Cat*.xml $ExistingUpdates = @(Get-ChildItem -Path "$OSBuilderContent\Updates\$Catalog\*" -Directory) } else { $CatalogsXmls = Get-ChildItem "$OSBuilderContent\Updates" Cat*.xml -Recurse $ExistingUpdates = @(Get-ChildItem -Path "$OSBuilderContent\Updates\*\*" -Directory) } #Exclude contents of the Custom directory #$ExistingUpdates = $ExistingUpdates | Where-Object {$_.FullName -notlike "*\Custom\*"} foreach ($CatalogsXml in $CatalogsXmls) { if ($($CatalogsXml.Name) -like "*Custom*") { #Write-Host "Processing Custom Catalog: $($CatalogsXml.FullName)" -ForegroundColor Green } $ImportCatalog = Import-Clixml -Path "$($CatalogsXml.FullName)" $CatalogDownloads += $ImportCatalog } $CatalogDownloads = $CatalogDownloads | Sort-Object DatePosted -Descending | Select-Object -Property Category, KBNumber, KBTitle, FileName, DatePosted, DateRevised, DateCreated, DateLastModified, URL #=================================================================================================== Write-Verbose '19.1.1 Get Downloaded and Superseded Updates' #=================================================================================================== foreach ($Update in $ExistingUpdates) { if ($CatalogDownloads.KBTitle -NotContains $Update.Name) {$SupersededUpdates += $Update.Name} else {$DownloadedUpdates += $Update.Name} } #=================================================================================================== Write-Verbose '19.1.1 Show Downloaded Updates' #=================================================================================================== if ($ShowDownloaded.IsPresent) { if ($DownloadedUpdates) { Write-Host "Downloaded Updates" -ForegroundColor Green $DownloadedUpdates Write-Host "" } } #=================================================================================================== Write-Verbose '19.1.1 Show Superseded Updates' #=================================================================================================== if (!($HideDetails.IsPresent)) { if ($SupersededUpdates) { Write-Host "Superseded Updates can be removed with -RemoveSuperseded" -ForegroundColor Green $SupersededUpdates Write-Host "" } } #=================================================================================================== Write-Verbose '19.1.1 Remove Superseded Updates' #=================================================================================================== if ($RemoveSuperseded.IsPresent){ foreach ($Update in $SupersededUpdates) { $RemoveUpdate = Get-ChildItem -Path "$OSBuilderContent\Updates\*\*" -Directory | Where-Object {$_.Name -eq $Update} Write-Warning "Removing $RemoveUpdate" Remove-Item -Path $RemoveUpdate -Recurse -Force } Write-Host "" } #=================================================================================================== #Write-Verbose '19.1.1 Show Available Updates' #=================================================================================================== <# foreach ($Update in $CatalogDownloads) { if ($ExistingUpdates.Name -NotContains $Update.KBTitle) { $AvailableUpdates += $Update.KBTitle } } if ($AvailableUpdates) { Write-Host "Available Updates that have not been downloaded" -ForegroundColor Green $AvailableUpdates Write-Host "" } #> #=================================================================================================== Write-Verbose '19.1.1 Filters' #=================================================================================================== #if (!($Catalog.IsPresent)) {$HideOptionalUpdates = $true} #if ($HideOptionalUpdates) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.Category -notlike "Language*"}} #if ($HideOptionalUpdates) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.Category -notlike "FeatureOnDemand"}} if (!($Catalog -or $FilterKBTitle)) { $CatalogDownloads = $CatalogDownloads | Where-Object {$_.Category -notlike "Language*"} $CatalogDownloads = $CatalogDownloads | Where-Object {$_.Category -notlike "FeatureOnDemand"} Write-Warning "Language Packs, Language Interface Packs and Features on Demand are not automatically displayed" Write-Warning "To view these updates, use the Catalog parameter" Write-Host "" } if ($FilterCategory) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.Category -like "*$FilterCategory*"}} if ($FilterKBNumber) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBNumber -like "*$FilterKBNumber*"}} if ($FilterKBNumber) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBNumber -like "*$FilterKBNumber*"}} if ($FilterKBTitle) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBTitle -like "*$FilterKBTitle*"}} if ($FilterLP) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBTitle -like "*$FilterLP*"}} if ($FilterLIP) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBTitle -like "*$FilterLIP*"}} if ($FilterOS) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBTitle -like "*$FilterOS*"}} if ($FilterOSArch) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBTitle -like "*$FilterOSArch*"}} if ($FilterOSBuild) {$CatalogDownloads = $CatalogDownloads | Where-Object {$_.KBTitle -like "*$FilterOSBuild*"}} #=================================================================================================== Write-Verbose '19.1.1 Select Updates with PowerShell ISE' #=================================================================================================== if ($IseGridView.IsPresent) {$CatalogDownloads = $CatalogDownloads | Out-GridView -PassThru -Title 'Select Updates to Download and press OK'} #=================================================================================================== Write-Verbose '19.1.1 Filtered Updates' #=================================================================================================== $FilteredUpdates = @() foreach ($Update in $CatalogDownloads) { if ($ExistingUpdates.Name -NotContains $Update.KBTitle) { $FilteredUpdates += $Update.KBTitle } } if (!($HideDetails.IsPresent)) { if ($FilteredUpdates) { Write-Host "Available Filtered Updates can be downloaded with the -Download parameter" -ForegroundColor Green $FilteredUpdates Write-Host "" } } #=================================================================================================== Write-Verbose '19.1.1 Download Updates' #=================================================================================================== if ($Download.IsPresent) { foreach ($Update in $CatalogDownloads) { $DownloadPath = "$OSBuilderContent\Updates\$($Update.Category)\$($Update.KBTitle)" $DownloadFullPath = "$DownloadPath\$($Update.FileName)" if (!(Test-Path $DownloadPath)) {New-Item -Path "$DownloadPath" -ItemType Directory -Force | Out-Null} if (!(Test-Path $DownloadFullPath)) { Write-Host "$DownloadFullPath" Write-Host "$($Update.URL)" -ForegroundColor Yellow Start-BitsTransfer -Source $($Update.URL) -Destination $DownloadFullPath } else { #Write-Warning "Exists: $($Update.KBTitle)" } } Write-Host "" } if (!($HideDetails.IsPresent)) { #=================================================================================================== Write-Verbose '19.1.1 Remove Variables' #=================================================================================================== Remove-Variable Catalog if ($CatalogsXml) {Remove-Variable CatalogsXml} Remove-Variable CatalogsXmls Remove-Variable Download Remove-Variable ExistingUpdates Remove-Variable FilterCategory Remove-Variable FilterKBNumber Remove-Variable FilterKBTitle Remove-Variable FilterLIP Remove-Variable FilterLP Remove-Variable FilterOS Remove-Variable FilterOSArch Remove-Variable FilterOSBuild Remove-Variable IseGridView Remove-Variable RemoveSuperseded Remove-Variable ShowDownloaded if ($Update) {Remove-Variable Update} Remove-Variable UpdateCatalogs } } END { #Write-Host '========================================================================================' -ForegroundColor DarkGray #Write-Host "$($MyInvocation.MyCommand.Name) END" -ForegroundColor Green } } |