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 XML catalog by file name from the module operating systems directory, derives the Windows release folder from that catalog name, 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' $latestXml = Get-ChildItem -Path $catalogDir -Filter '*.xml' -File | Sort-Object Name -Descending | Select-Object -First 1 if (-not $latestXml) { Write-Warning "[$(Get-Date -Format s)] No 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 # ------------------------------------------------------------------------- # Derive OS folder name from the catalog filename # e.g. '26200.8457-win11-25h2.xml' → 'Windows 11 25H2' # ------------------------------------------------------------------------- $catalogBase = [System.IO.Path]::GetFileNameWithoutExtension($latestXml.Name) if ($catalogBase -notmatch '^\d+\.\d+-win(\d+)-(.+)$') { Write-Warning "[$(Get-Date -Format s)] Cannot parse OS version from catalog name '$($latestXml.Name)'. Expected format: '<build>-win<version>-<release>.xml' (e.g. '26200.8457-win11-25h2.xml')." return } $osFolderName = "Windows $($Matches[1]) $($Matches[2].ToUpper())" 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() } |