private/BootMedia/WindowsOS/Get-WimIndexCache.ps1

#Requires -Version 7.4

function Get-WimIndexCache {
    <#
    .SYNOPSIS
        Returns cached or freshly-queried Windows image index data for a WIM/ESD file.
 
    .DESCRIPTION
        Computes the SHA256 hash of the specified image file and checks the cache directory
        for a matching JSON file. On cache hit, the stored image index data is returned
        without calling Get-WindowsImage. On cache miss, Get-WindowsImage is called for
        each index in the image file, the results are saved to the cache, and then returned.
 
        Cache files are stored at $Script:OSDeployCorePath\cache\{sha256}.json.
 
    .PARAMETER ImagePath
        The full path to the install.wim or install.esd file.
 
    .OUTPUTS
        [PSCustomObject[]] Array of image index detail objects (same shape as Get-WindowsImage
        -ImagePath -Index output).
 
    .NOTES
        Author: David Segura
        Version: 0.1.0
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$ImagePath
    )

    $CacheDirectory = Join-Path $Script:OSDeployCorePath 'cache' 'hashes'
    if (-not (Test-Path -Path $CacheDirectory)) {
        New-Item -ItemType Directory -Path $CacheDirectory -Force | Out-Null
    }

    # Compute SHA256 hash of the image file
    Write-OSDeployCoreProgress "Computing SHA256 hash: $ImagePath"
    $FileHash = (Get-FileHash -Path $ImagePath -Algorithm SHA256).Hash
    Write-Verbose "[$($MyInvocation.MyCommand.Name)] SHA256: $FileHash"

    $CacheFilePath = Join-Path $CacheDirectory "$FileHash.json"

    # Check for cache hit
    if (Test-Path -Path $CacheFilePath) {
        Write-OSDeployCoreProgress "Using cached image index for $FileHash"
        $CacheData = Get-Content -Path $CacheFilePath -Raw | ConvertFrom-Json
        return $CacheData.Images
    }

    # Cache miss - query DISM for all indexes
    Write-OSDeployCoreProgress "Querying image indexes (no cache): $ImagePath"
    $IndexList = Get-WindowsImage -ImagePath $ImagePath

    $ImageDetails = foreach ($Entry in $IndexList) {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Querying index $($Entry.ImageIndex): $($Entry.ImageName)"
        Get-WindowsImage -ImagePath $Entry.ImagePath -Index $Entry.ImageIndex
    }

    # Build cache object
    $FileInfo = Get-Item -Path $ImagePath
    $CacheObject = [ordered]@{
        Hash       = $FileHash
        ImagePath  = $ImagePath
        FileSize   = $FileInfo.Length
        CachedTime = (Get-Date).ToString('o')
        ImageCount = @($ImageDetails).Count
        Images     = @($ImageDetails | ForEach-Object {
            # Select only serializable properties
            $_ | Select-Object -Property ImagePath, ImageIndex, ImageName, ImageDescription,
                ImageSize, WIMBoot, Architecture, Hal, Version,
                SPBuild, SPLevel, EditionId, InstallationType,
                ProductName, ProductType, ProductSuite,
                Languages, DefaultLanguageIndex,
                DirectoryCount, FileCount,
                CreatedTime, ModifiedTime,
                MajorVersion, MinorVersion, Build,
                ImageBootable, SystemRoot,
                LogPath, ScratchDirectory, LogLevel, ImageType
        })
    }

    # Save to cache
    $CacheObject | ConvertTo-Json -Depth 5 |
        Out-File -FilePath $CacheFilePath -Encoding utf8 -Force
    Write-OSDeployCoreProgress "Cached image index: $FileHash"

    return $CacheObject.Images
}