Windows ESD Catalogs
Understand how OSDeploy uses the Windows ESD catalog to select, download, cache, and verify Windows 11 media.
This article steps through the code behind Update-OSDeployCoreESD to show how OSDeploy turns a Windows ESD catalog into a verified file in the local cache.
The catalog is the function's source of truth. It connects a Windows release, language, edition, and architecture to a specific ESD file on the Microsoft Content Delivery Network.
The bundled catalog may not contain the newest Windows release available from Microsoft. It contains the latest OS that has been tested with OSDeploy and verified to work. This favors a known working deployment source over unverified media simply because it is newer.
The catalog is included with the OSDeploy module under:
OSDeploy\core\operatingsystems\Each XML file describes one Windows release. The catalog file name contains the Windows build and release:
26200.8653-win11-25h2.xml26200.8653
Windows build and revision
win11
Windows 11
25h2
Windows 11, version 25H2
Catalog names change when newer media is tested and added to OSDeploy. The function sorts the bundled catalog files by name and selects the first one.
Follow the Code Path
The function handles the catalog in three stages before a download begins:
Resolve and parse the latest bundled catalog.
Build target records and match them against the catalog.
Check the cache and URL before asking the user to download.
After confirmation, a separate download loop resumes transfers, handles retries, and verifies SHA256. Keeping discovery separate from transfer allows the function to evaluate every requested architecture before downloading any file.
Resolve the Catalog
The function starts from $script:OSDeployModuleBase, which points to the installed module. It enumerates the XML files, sorts their names in descending order, and separates the first catalog from the older catalogs:
The file naming convention makes this sort meaningful because the build and revision appear first. If the directory contains no XML files, the function throws a terminating CatalogNotFound error instead of continuing without trusted metadata.
The selected XML is then cast directly to an XML document. The expression assigned to $allFiles moves through the document hierarchy and returns every File element:
Catalog Structure
The XML hierarchy leads to a collection of File elements:
Each File element is a logical media record. The fields used by OSDeploy are:
FileName
Name used for the cached ESD
LanguageCode
Windows language and region, such as en-us
Language
Display name for the language
Edition
Windows edition represented by the record
Architecture
Media architecture: x64 or ARM64
Size
File size in bytes
Sha256
SHA256 checksum used to verify the ESD
FilePath
Microsoft Content Delivery Network URL
An abbreviated Enterprise record looks like this:
The same physical ESD can appear in several logical records. Microsoft business or consumer media can contain multiple Windows editions, so records for different editions can share the same file name, URL, size, and checksum. Select by the requested edition rather than assuming every record points to a unique file.
Build the Target List
The catalog contains far more media than Update-OSDeployCoreESD needs. The function first creates small target objects that describe the records it wants. On AMD64 Windows, that target list is equivalent to:
On ARM64 Windows, only the ARM64 object is created. The public parameter uses amd64, but the catalog uses x64, so an internal map translates between the two vocabularies:
Wrapping the filtered result in @(...) keeps $targets array-shaped even when only one record remains.
Match the Catalog Records
For each target, the function filters all catalog records by three fields:
Select-Object -First 1 matters because one physical ESD can be represented by several logical edition records. The function needs one matching Enterprise record per requested architecture, not every record that refers to the same media.
-Architecture amd64
x64
-Architecture arm64
ARM64
The catalog can contain both architectures; the OSDeploy PC and -Architecture parameter control which records are eligible for selection.
Only the first matching record is selected for each architecture. If no matching Enterprise en-US record exists, the command writes a warning and skips that architecture.
Derive the Cache Directory
The function does not hard-code Windows 11 25H2. It parses that label from the selected catalog name:
For 26200.8653-win11-25h2.xml, the capture groups contain 11 and 25h2, producing:
The build revision is intentionally absent from the directory. New tested media for the same Windows release uses the same folder but has a different ESD file name.
Phase 1: Classify Each Entry
The first processing loop does not immediately download anything. It classifies every resolved entry into one of these outcomes:
Current file exists and SHA256 matches
Add it directly to $results
Current file exists and SHA256 differs
Offer to recycle it and continue
Verified older file exists
Offer to keep it or use the newer catalog entry
URL cannot be reached
Warn and skip the entry
URL is reachable
Add the entry to $pendingEntries
The expected hash is normalized before comparison:
Removing whitespace and normalizing case prevents formatting differences from changing the checksum comparison.
Older catalogs are not fallback download sources. The function reads them only to identify an older file already present in the current release folder. That file is accepted only when its SHA256 matches its own catalog record.
Before an uncached entry reaches the confirmation prompt, curl.exe sends a HEAD request with a 15-second limit:
This prevents an unavailable catalog URL from being presented as a viable download.
Phase 2: Confirm Before Transfer
The function loops through $pendingEntries, calculates a display size from the catalog, and asks for confirmation. Approved entries move into $confirmedEntries:
ShouldContinue provides the interactive Yes/No choice. ShouldProcess integrates the operation with -WhatIf. No transfer begins until all pending entries have passed through this phase.
Phase 3: Download and Verify
The download loop first requests Content-Length and Accept-Ranges from the server. Those headers determine whether the function can detect an incomplete resumable transfer by comparing local and remote byte counts.
The curl.exe arguments enable redirects, HTTP failure handling, internal curl retries, and continuation of a partial file:
Around curl's own retry behavior, the function has an outer retry loop with three automatic attempts. Each attempt is classified as one of four failures:
DownloadFailed
curl.exe returns a nonzero exit code
DownloadMissing
curl returns success but no output file exists
DownloadIncomplete
resumable local length is below the remote length
ChecksumMismatch
local SHA256 differs from the catalog
A matching SHA256 sets $downloadSucceeded to $true. Only then is the FileInfo added to $results. After automatic attempts are exhausted, the function reports the relevant details and offers a manual retry.
Checksum failures are handled differently from incomplete transfers. A partial file can be resumed, but a complete file with the wrong checksum is moved to the Recycle Bin so the next attempt starts cleanly.
Do not treat a familiar file name or a completed download as proof that an ESD is valid. The file is ready only after its SHA256 matches the same catalog record that supplied its URL.
Inspect the Installed Catalog
Import OSDeploy, locate the latest catalog, and load it as XML:
Review the available architectures, languages, and editions:
Display the records selected by OSDeploy:
Convert the byte count to GiB when reviewing media size:
Why the Catalog Is Bundled
Bundling the catalog with the module makes media selection deterministic. A particular OSDeploy module version carries a known set of ESD metadata, and the download is accepted only when it matches that metadata.
Updating the OSDeploy module can therefore update the available Windows media without changing the Update-OSDeployCoreESD command. The command supplies the selection and verification behavior; the catalog supplies the release-specific data.
Related
Last updated
Was this helpful?

