private/Get-OSDeployCoreESD.ps1
|
#Requires -PSEdition Core #Requires -Version 7.4 function Get-OSDeployCoreESD { <# .SYNOPSIS Gets verified ESD files from the OSDeployCore cache .DESCRIPTION Selects the newest recognized XML catalog by parsed build and release timestamp from the module operating systems directory, resolves its Windows release folder, and checks the corresponding cached en-US Enterprise ESD files for x64 and ARM64, optionally limited to one architecture. Each file's SHA256 hash must match its catalog entry. Missing catalog entries, files, malformed catalog names, and checksum mismatches produce warnings and are excluded. The function does not download, delete, or modify ESD files. .PARAMETER Architecture Limits cache verification to amd64 or arm64. When omitted, verifies both architectures. .EXAMPLE PS> Get-OSDeployCoreESD Returns cached en-US Enterprise ESD files whose SHA256 hashes match the newest module catalog. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.IO.FileInfo. Returns zero, one, or two verified ESD files, with at most one file for each of the x64 and ARM64 targets. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-08-28 Run Update-OSDeployCoreESD to download missing or outdated ESD files. Dependencies: DotNet Classes: System.Collections.Generic.List[System.IO.FileInfo], System.IO.FileInfo, System.IO.Path #> [CmdletBinding()] [OutputType([System.IO.FileInfo[]])] param ( [Parameter()] [ValidateSet('amd64', 'arm64')] [System.String] $Architecture ) Write-Verbose "[$($MyInvocation.MyCommand.Name)] Start" # ------------------------------------------------------------------------- # Resolve catalog files (latest first) # ------------------------------------------------------------------------- $catalogDir = Join-Path $script:OSDeployModuleBase 'core\operatingsystems' $catalogRecords = foreach ($catalogFile in Get-ChildItem -Path $catalogDir -Filter '26200*.xml' -File) { try { $catalogMetadata = Get-OSDeployCatalogMetadata -Name $catalogFile.Name } catch { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Ignoring unrecognized catalog filename: $($catalogFile.FullName)" continue } [pscustomobject]@{ Build = $catalogMetadata.Build ReleaseDateTime = $catalogMetadata.ReleaseDateTime OSFolderName = $catalogMetadata.OSFolderName File = $catalogFile } } $latestCatalogRecord = $catalogRecords | Sort-Object @{ Expression = 'Build'; Descending = $true }, @{ Expression = 'ReleaseDateTime'; Descending = $true } | Select-Object -First 1 $latestXml = $latestCatalogRecord.File if (-not $latestXml) { Write-Warning "[$(Get-Date -Format s)] No recognized OS catalog XML files found in '$catalogDir'." return } Write-Verbose "[$($MyInvocation.MyCommand.Name)] Using catalog: $($latestXml.Name)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Importing OSDeploy PSModule OperatingSystem Catalog" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] $($latestXml.FullName)" # ------------------------------------------------------------------------- # Parse the catalog # ------------------------------------------------------------------------- [xml]$catalog = Get-Content -Path $latestXml.FullName -Raw $allFiles = $catalog.MCT.Catalogs.Catalog.PublishedMedia.Files.File # ------------------------------------------------------------------------- # Resolve the Windows release folder from the parsed catalog build. # ------------------------------------------------------------------------- $osFolderName = $latestCatalogRecord.OSFolderName Write-Verbose "[$($MyInvocation.MyCommand.Name)] OS folder name: $osFolderName" # ------------------------------------------------------------------------- # Locate the download directory # ------------------------------------------------------------------------- $downloadDir = Join-Path $script:OSDeployCorePath 'OSDCloud' 'OS' $osFolderName Write-Verbose "[$($MyInvocation.MyCommand.Name)] Download directory: $downloadDir" # ------------------------------------------------------------------------- # Target the requested architecture, or both when no filter is specified. # ------------------------------------------------------------------------- $targets = switch ($Architecture) { 'amd64' { [pscustomobject]@{ Architecture = 'x64'; Edition = 'Enterprise'; LanguageCode = 'en-us' } } 'arm64' { [pscustomobject]@{ Architecture = 'ARM64'; Edition = 'Enterprise'; LanguageCode = 'en-us' } } default { [pscustomobject]@{ Architecture = 'x64'; Edition = 'Enterprise'; LanguageCode = 'en-us' } [pscustomobject]@{ Architecture = 'ARM64'; Edition = 'Enterprise'; LanguageCode = 'en-us' } } } $normalizeHash = { param([string]$hash) ($hash -replace '\s+', '').ToUpperInvariant() } $results = [System.Collections.Generic.List[System.IO.FileInfo]]::new() foreach ($target in $targets) { $entry = $allFiles | Where-Object { $_.LanguageCode -eq $target.LanguageCode -and $_.Edition -eq $target.Edition -and $_.Architecture -eq $target.Architecture } | Select-Object -First 1 if (-not $entry) { Write-Warning "[$(Get-Date -Format s)] No catalog entry found for $($target.Edition) $($target.Architecture) $($target.LanguageCode). Skipping." continue } $destPath = Join-Path $downloadDir $entry.FileName Write-Verbose "[$($MyInvocation.MyCommand.Name)] Checking: $($entry.FileName)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Verifying OSDeployCoreESD for Windows 11 $($target.Edition) $($target.LanguageCode) $($target.Architecture)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] FileName: $($entry.FileName)" if (-not (Test-Path -Path $destPath -PathType Leaf)) { Write-Warning "[$(Get-Date -Format s)] ESD not found in cache: $destPath" Write-Warning "[$(Get-Date -Format s)] Run Update-OSDeployCoreESD to download it." continue } $expectedSha256 = & $normalizeHash $entry.Sha256 $actualHash = (Get-FileHash -Path $destPath -Algorithm SHA256).Hash.ToUpperInvariant() if ($actualHash -ne $expectedSha256) { Write-Warning "[$(Get-Date -Format s)] SHA256 mismatch for '$($entry.FileName)'." Write-Warning "[$(Get-Date -Format s)] Expected : $expectedSha256" Write-Warning "[$(Get-Date -Format s)] Actual : $actualHash" Write-Warning "[$(Get-Date -Format s)] Run Update-OSDeployCoreESD to re-download it." continue } Write-Verbose "[$($MyInvocation.MyCommand.Name)] SHA256 verified: $($entry.FileName)" # Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] ESD cached and verified: $($entry.FileName)" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Hash SHA256: $actualHash" $results.Add((Get-Item -Path $destPath)) } Write-Verbose "[$($MyInvocation.MyCommand.Name)] Done. $($results.Count) file(s) verified." return $results.ToArray() } |