private/Get-OSDeployCoreESD.ps1
|
#Requires -PSEdition Core #Requires -Version 7.4 function Get-OSDeployCoreESD { <# .SYNOPSIS Returns verified ESD files from the OSDeployCore OSDCloud OS cache. .DESCRIPTION Resolves the latest OS catalog XML from the OSDeploy module's catalogs\operatingsystem directory, then checks whether the corresponding en-US Enterprise ESD files for both x64 (amd64) and ARM64 have already been downloaded to C:\ProgramData\OSDeployCore\OSDCloud\OS\<Version>. For each architecture, if the file is present its SHA256 checksum is verified against the catalog value. Files that are missing or that fail the checksum check are excluded from output and a warning is written. Only files that exist and whose checksum matches are returned. This function is read-only: it does not download, delete, or prompt the user. .OUTPUTS System.IO.FileInfo. One FileInfo object per verified ESD file found in the cache (up to two objects: x64 and ARM64). .EXAMPLE Get-OSDeployCoreESD Returns FileInfo objects for any en-US Enterprise ESD files that are already cached and SHA256-verified against the latest catalog. .EXAMPLE $esds = Get-OSDeployCoreESD $esds | Select-Object Name, Length Lists the name and size of each verified cached ESD. .NOTES Run Update-OSDeployCoreESD to download missing or outdated ESD files. #> [CmdletBinding()] [OutputType([System.IO.FileInfo[]])] param () Write-Verbose "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Start" # ------------------------------------------------------------------------- # Resolve catalog files (latest first) # ------------------------------------------------------------------------- $catalogDir = Join-Path $script:OSDeployModuleBase 'catalogs\operatingsystem' $latestXml = Get-ChildItem -Path $catalogDir -Filter '*.xml' -File | Sort-Object Name -Descending | Select-Object -First 1 if (-not $latestXml) { Write-Warning "[$($MyInvocation.MyCommand.Name)] No OS catalog XML files found in '$catalogDir'." return } Write-Verbose "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Using catalog: $($latestXml.Name)" Write-OSDeployCoreProgress "Checking Operating System Catalog at $($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 "[$($MyInvocation.MyCommand.Name)] 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 "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] OS folder name: $osFolderName" # ------------------------------------------------------------------------- # Locate the download directory # ------------------------------------------------------------------------- $downloadDir = Join-Path $script:OSDeployCorePath 'OSDCloud' 'OS' $osFolderName Write-Verbose "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Download directory: $downloadDir" # ------------------------------------------------------------------------- # Target both architectures regardless of host architecture # ------------------------------------------------------------------------- $targets = @( [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 "[$($MyInvocation.MyCommand.Name)] No catalog entry found for $($target.Edition) $($target.Architecture) $($target.LanguageCode). Skipping." continue } $destPath = Join-Path $downloadDir $entry.FileName Write-Verbose "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Checking: $($entry.FileName)" Write-OSDeployCoreProgress "Checking cache for $($entry.FileName)" if (-not (Test-Path -Path $destPath -PathType Leaf)) { Write-Warning "[$($MyInvocation.MyCommand.Name)] ESD not found in cache: $destPath" Write-Warning "[$($MyInvocation.MyCommand.Name)] 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 "[$($MyInvocation.MyCommand.Name)] SHA256 mismatch for '$($entry.FileName)'." Write-Warning "[$($MyInvocation.MyCommand.Name)] Expected : $expectedSha256" Write-Warning "[$($MyInvocation.MyCommand.Name)] Actual : $actualHash" Write-Warning "[$($MyInvocation.MyCommand.Name)] Run Update-OSDeployCoreESD to re-download it." continue } Write-Verbose "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] SHA256 verified: $($entry.FileName)" Write-OSDeployCoreProgress "ESD cached and verified: $($entry.FileName)" Write-OSDeployCoreProgress " SHA256 : $actualHash" $results.Add((Get-Item -Path $destPath)) } Write-Verbose "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Complete. $($results.Count) file(s) verified." return $results.ToArray() } |