private/Get-WimIndexCache.ps1

#Requires -Version 7.4

function Get-WimIndexCache {
    <#
    .SYNOPSIS
        Gets cached Windows image index metadata
 
    .DESCRIPTION
        Computes the SHA256 hash of an image and reads its image index metadata from
        $Script:OSDeployCorePath\cache\hashes\<hash>.json when present. On a cache miss, the
        function queries every index with Get-WindowsImage, selects serializable metadata,
        and writes a UTF-8 JSON cache file before returning the rows. The cache directory is
        created when absent.
 
    .PARAMETER ImagePath
        Specifies the WIM or ESD image to hash and query. Get-FileHash, Get-Item, and
        Get-WindowsImage enforce path validity.
 
    .EXAMPLE
        PS> Get-WimIndexCache -ImagePath 'D:\sources\install.wim'
 
        Returns cached index metadata for install.wim or queries the image and creates its
        hash-keyed JSON cache file.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns zero or more image index rows
        containing the selected image identity, size, architecture, version, edition,
        language, count, timestamp, boot, path, and logging properties. Cached rows are
        deserialized JSON objects; fresh rows are selected PowerShell objects.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 0.1.0
        Date: 2026-08-28
 
        Dependencies:
          PowerShell Modules: Dism
          DotNet Classes: System.Management.Automation.PSCustomObject
    #>

    [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-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Computing Hash SHA256: $ImagePath"
    $FileHash = (Get-FileHash -Path $ImagePath -Algorithm SHA256).Hash
    Write-Verbose "[$($MyInvocation.MyCommand.Name)] Hash SHA256: $FileHash"

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

    # Check for cache hit
    if (Test-Path -Path $CacheFilePath) {
        Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] 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-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] 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-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Cached image index: $FileHash"

    return $CacheObject.Images
}