public/Update-OSDeployCoreCatalogs.ps1
|
#Requires -PSEdition Core #Requires -Version 7.4 function Update-OSDeployCoreCatalogs { <# .SYNOPSIS Updates OSDeploy operating system catalogs .DESCRIPTION Runs the module's validated Windows 11 25H2 catalog updater when the module operating system catalog directory is writable. After validation and publication, copies the current catalog to the OSDeploy Core OSDCloud catalog directory under OSDCloud\catalogs\operatingsystems. Existing module catalogs remain in place. Any prerequisite, download, validation, publication, or cache-copy failure is reported as a warning and does not produce a terminating error. .PARAMETER MinimumItemCount Specifies the minimum number of ESD records required before a catalog is accepted. The default is 50. Valid values are 1 through 100000. .EXAMPLE PS> Update-OSDeployCoreCatalogs Updates the module operating system catalog and synchronizes it to the OSDeploy Core catalog cache. .EXAMPLE PS> Update-OSDeployCoreCatalogs -WhatIf Downloads and validates the current catalog, then previews module publication and cache synchronization without changing either location. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject. Returns the detected build, module and cache catalog paths, publication and cache-copy status, item count, and SHA256 hash after successful catalog validation. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-09-17 Requires Windows, PowerShell 7.4 or later, internet access, expand.exe, writable temporary storage, and write access to the module catalog and OSDeploy Core cache directories when updating. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'The public command name explicitly represents multiple module catalog types.')] [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] [OutputType([System.Management.Automation.PSCustomObject])] param ( [Parameter()] [ValidateRange(1, 100000)] [int] $MinimumItemCount = 50 ) $functionName = $MyInvocation.MyCommand.Name $moduleCatalogDirectory = Join-Path $script:OSDeployModuleBase 'core\operatingsystems' $updaterPath = Join-Path $script:OSDeployModuleBase 'core\scripts\update-operatingsystems.ps1' $cacheCatalogDirectory = Join-Path $script:OSDeployCorePath 'OSDCloud\catalogs\operatingsystems' $writeProbePath = $null try { if (-not $IsWindows) { throw 'Windows is required.' } if (-not (Test-Path -LiteralPath $updaterPath -PathType Leaf)) { throw "Catalog updater was not found at '$updaterPath'." } if (-not (Test-Path -LiteralPath $moduleCatalogDirectory -PathType Container)) { throw "Module catalog directory was not found at '$moduleCatalogDirectory'." } # A create-and-delete probe verifies effective write access instead of inferring it from ACLs. if (-not $WhatIfPreference) { $writeProbePath = Join-Path $moduleCatalogDirectory ('.write-test-' + [guid]::NewGuid() + '.tmp') $writeProbe = [System.IO.File]::Open( $writeProbePath, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None ) $writeProbe.Dispose() Remove-Item -LiteralPath $writeProbePath -Force $writeProbePath = $null } $operation = 'Update module operating system catalogs and synchronize the OSDeploy Core catalog cache' $approved = $PSCmdlet.ShouldProcess($moduleCatalogDirectory, $operation) if (-not $approved -and -not $WhatIfPreference) { return } # The updater retains acquisition and integrity validation under WhatIf. $updateResult = & $updaterPath ` -MinimumItemCount $MinimumItemCount ` -WhatIf:$WhatIfPreference ` -Confirm:$false if (-not $updateResult) { throw 'Catalog updater returned no validation result.' } $cacheCatalogPath = Join-Path $cacheCatalogDirectory ([System.IO.Path]::GetFileName($updateResult.DestinationPath)) $cached = $false if (-not $WhatIfPreference) { if (-not (Test-Path -LiteralPath $updateResult.DestinationPath -PathType Leaf)) { throw "Validated catalog was not found at '$($updateResult.DestinationPath)'." } # Stage in the cache directory so replacement cannot expose a partial catalog. $null = New-Item -Path $cacheCatalogDirectory -ItemType Directory -Force $stagedCachePath = Join-Path $cacheCatalogDirectory ('.' + [System.IO.Path]::GetFileName($cacheCatalogPath) + '.' + [guid]::NewGuid() + '.tmp') try { [System.IO.File]::Copy($updateResult.DestinationPath, $stagedCachePath, $false) [System.IO.File]::Move($stagedCachePath, $cacheCatalogPath, $true) } finally { if (Test-Path -LiteralPath $stagedCachePath -PathType Leaf) { Remove-Item -LiteralPath $stagedCachePath -Force -ErrorAction SilentlyContinue } } $cached = $true } [pscustomobject]@{ Build = $updateResult.Build ModuleCatalogPath = $updateResult.DestinationPath CacheCatalogPath = $cacheCatalogPath Published = [bool]$updateResult.Published Cached = $cached ItemCount = $updateResult.ItemCount Sha256 = $updateResult.Sha256 } } catch { Write-Warning "[$(Get-Date -Format s)] [$functionName] Catalog update was not successful. $($_.Exception.Message)" } finally { if ($writeProbePath -and (Test-Path -LiteralPath $writeProbePath -PathType Leaf)) { Remove-Item -LiteralPath $writeProbePath -Force -ErrorAction SilentlyContinue } } } |