private/core-cache/Get-OSDCoreCacheContent.ps1

function Get-OSDCoreCacheContent {
    <#
    .SYNOPSIS
        Returns cached OSDCloud content found on local file system drives.
 
    .DESCRIPTION
        Enumerates mounted file system drives and discovers OSDCloud cache content.
        Returns objects with Type, Name, FullName, SizeMB,
        DriveRoot, VolumeLabel, VolumeUniqueId, and USB properties.
        Exports the returned object to $env:Temp\OSDCoreCache.xml each time the function runs.
 
        If Type is omitted, returns all supported cache content types.
 
        Type values:
        - ESD: All .esd files under '<DriveLetter>:\OSDCloud\OS' recursively.
        - ISO: All .iso files under '<DriveLetter>:\OSDCloud\ISO' recursively.
        - DriverPacks: All .cab, .exe, .msi, and .zip files under
          '<DriveLetter>:\OSDCloud\DriverPacks' recursively.
        - Drivers: Immediate folders under '<DriveLetter>:\OSDCloud\Drivers' that
          contain at least one .inf file in any child folder.
        - ModelDrivers: Immediate folders under 'OSDCloud\modeldrivers-amd64' and
          'OSDCloud\modeldrivers-arm64' containing .inf files recursively. Names use
          '<osdmanufacturer>_<osdproduct>_<osdmodel>_<osbuild>'. Model text is
          descriptive; deployment matches manufacturer/product and selects the
          highest numeric folder build, regardless of the deployed OS build.
        - WinPEDrivers: Immediate folders under 'OSDCloud\winpedrivers-amd64' and
          'OSDCloud\winpedrivers-arm64' with the same naming and INF requirements
          as ModelDrivers. Discovered for inventory only; not used in deployment.
        - Profiles: Immediate folders under '<DriveLetter>:\OSDCloud\Profiles'.
        - WIM: All .wim files under '<DriveLetter>:\OSDCloud\WIM' recursively.
        - *: Includes all supported Type values.
 
    .PARAMETER Type
        Optional cache content selector.
 
        Supports one or more values. Use '*' to return all supported
        cache content types.
 
    .PARAMETER Include
        Optional list of drive letters to include when searching for OSDCloud cache
        content. Accepts values such as 'C', 'D:', or 'E:\'.
 
        When omitted, all mounted file system drive letters are considered.
 
    .PARAMETER Exclude
        Optional list of drive letters to exclude when searching for OSDCloud cache
        content. Accepts values such as 'C', 'D:', or 'E:\'.
 
        Excluded drives are skipped even when they are also present in Include.
 
    .OUTPUTS
        System.Object[]. Objects with Type, Name, FullName, SizeMB,
        DriveRoot, VolumeLabel, VolumeUniqueId, and USB.
        ModelDrivers and WinPEDrivers also include OSArchitecture, OSBuildVersion, and ModelIdentity
        (the folder name without its trailing build).
 
    .NOTES
        ModelDrivers discovery does not guarantee that a source is safe for deployment.
        Deployment excludes sources on disks that will be cleared.
 
    .EXAMPLE
        Get-OSDCoreCacheContent
 
        Returns all supported cache content types.
 
    .EXAMPLE
        Get-OSDCoreCacheContent -Type ESD
 
        Returns all .esd files under each discovered cache OS folder.
 
    .EXAMPLE
        Get-OSDCoreCacheContent -Type ESD,DriverPacks
 
        Returns all .esd files and driver pack files from each discovered cache.
 
    .EXAMPLE
        Get-OSDCoreCacheContent -Type ModelDrivers
 
        Returns model-specific driver folders for both architectures.
 
    .EXAMPLE
        Get-OSDCoreCacheContent -Type WinPEDrivers
 
        Returns cached WinPE driver folders for both architectures.
 
    .EXAMPLE
        Get-OSDCoreCacheContent -Type *
 
        Returns all supported cache content types.
 
    .EXAMPLE
        Get-OSDCoreCacheContent -Include C,D -Exclude D
 
        Searches only drive C for supported cache content types.
    #>

    [CmdletBinding()]
    [OutputType([System.Object[]])]
    param (
        [Parameter()]
        [ValidateSet('ESD', 'ISO', 'DriverPacks', 'Drivers', 'ModelDrivers', 'WinPEDrivers', 'Profiles', 'WIM', '*')]
        [string[]]$Type,

        [Parameter()]
        [ValidatePattern('^[a-zA-Z](:\\)?$|^[a-zA-Z]$')]
        [string[]]$Include,

        [Parameter()]
        [ValidatePattern('^[a-zA-Z](:\\)?$|^[a-zA-Z]$')]
        [string[]]$Exclude
    )

    $Error.Clear()
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Start"
    # Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] OSDCoreCacheContent is updating"

    function Get-FileOnlySizeMB {
        param(
            [Parameter(Mandatory)]
            [string]$Path
        )

        if (-not (Test-Path -LiteralPath $Path)) {
            return 0
        }

        $item = Get-Item -LiteralPath $Path -ErrorAction SilentlyContinue
        if (-not $item) {
            return 0
        }

        if ($item.PSIsContainer) {
            $totalBytes = (Get-ChildItem -LiteralPath $Path -Recurse -File -ErrorAction SilentlyContinue |
                Measure-Object -Property Length -Sum).Sum
            if ($null -eq $totalBytes) {
                $totalBytes = 0
            }
            return [math]::Round(($totalBytes / 1MB), 2)
        }

        return [math]::Round((([int64]$item.Length) / 1MB), 2)
    }

    function Get-DriveVolumeMetadata {
        param(
            [Parameter(Mandatory)]
            [string]$DriveRoot
        )

        $volume = $null
        $usb = $false
        if ($DriveRoot -match '^[A-Z]:\\$') {
            try {
                $driveLetter = $DriveRoot.Substring(0, 1)
                $volume = Get-Volume -DriveLetter $driveLetter -ErrorAction Stop
                $usb = [bool](Get-Disk -ErrorAction SilentlyContinue |
                    Where-Object { $_.BusType -eq 'USB' } |
                    Get-Partition -ErrorAction SilentlyContinue |
                    Where-Object { $_.DriveLetter -eq $driveLetter })
            } catch {
                $volume = $null
                $usb = $false
            }
        }

        return [PSCustomObject]@{
            DriveRoot      = $DriveRoot
            VolumeLabel    = if ($volume) { [string]$volume.FileSystemLabel } else { $null }
            VolumeUniqueId = if ($volume) { [string]$volume.UniqueId } else { $null }
            USB            = [bool]$usb
        }
    }

    function New-CacheResultObject {
        param(
            [Parameter(Mandatory)]
            [string]$ResultType,

            [Parameter(Mandatory)]
            [string]$ResultFullName,

            [Parameter(Mandatory)]
            $VolumeMetadata
        )

        [PSCustomObject]@{
            Type           = $ResultType
            Name           = Split-Path -Path $ResultFullName -Leaf
            FullName       = $ResultFullName
            SizeMB         = Get-FileOnlySizeMB -Path $ResultFullName
            USB            = [bool]$VolumeMetadata.USB
            DriveRoot      = [string]$VolumeMetadata.DriveRoot
            VolumeLabel    = [string]$VolumeMetadata.VolumeLabel
            VolumeUniqueId = [string]$VolumeMetadata.VolumeUniqueId
        }
    }

    function ConvertTo-DriveLetterList {
        param(
            [Parameter()]
            [string[]]$DriveLetters
        )

        $normalized = foreach ($driveLetter in $DriveLetters) {
            if ([string]::IsNullOrWhiteSpace($driveLetter)) {
                continue
            }

            $value = $driveLetter.Trim().TrimEnd('\\')
            if ($value.Length -lt 1) {
                continue
            }

            $letter = $value.Substring(0, 1).ToUpperInvariant()
            if ($letter -match '^[A-Z]$') {
                $letter
            }
        }

        @($normalized | Sort-Object -Unique)
    }

    $includedDriveLetters = ConvertTo-DriveLetterList -DriveLetters $Include
    $excludedDriveLetters = ConvertTo-DriveLetterList -DriveLetters $Exclude

    $cachePaths = Get-PSDrive -PSProvider FileSystem |
        Where-Object { $_.Root -match '^[A-Z]:\\$' } |
        Where-Object {
            $driveLetter = ([string]$_.Root).Substring(0, 1).ToUpperInvariant()
            (($includedDriveLetters.Count -eq 0) -or ($driveLetter -in $includedDriveLetters)) -and
            ($driveLetter -notin $excludedDriveLetters)
        } |
        ForEach-Object {
            $driveRoot = [string]$_.Root
            $osdCloudPath = Join-Path -Path $driveRoot -ChildPath 'OSDCloud'

            if (Test-Path -LiteralPath $osdCloudPath) {
                $volumeMetadata = Get-DriveVolumeMetadata -DriveRoot $driveRoot
                [PSCustomObject]@{
                    CachePath      = $osdCloudPath
                    VolumeMetadata = $volumeMetadata
                }
            }
        }

    $cachePaths = @($cachePaths | Sort-Object -Property CachePath -Unique)

    $selectedTypes = if ($PSBoundParameters.ContainsKey('Type')) {
        @($Type | Sort-Object -Unique)
    } else {
        @('ESD', 'ISO', 'DriverPacks', 'Drivers', 'ModelDrivers', 'WinPEDrivers', 'Profiles', 'WIM')
    }
    if ($selectedTypes -contains '*') {
        $selectedTypes = @('ESD', 'ISO', 'DriverPacks', 'Drivers', 'ModelDrivers', 'WinPEDrivers', 'Profiles', 'WIM')
    }

    $result = foreach ($selectedType in $selectedTypes) {
        switch ($selectedType) {
            'ESD' {
                foreach ($cacheEntry in $cachePaths) {
                    $osPath = Join-Path -Path $cacheEntry.CachePath -ChildPath 'OS'
                    if (Test-Path -LiteralPath $osPath) {
                        Get-ChildItem -LiteralPath $osPath -Recurse -File -Filter '*.esd' -ErrorAction SilentlyContinue |
                            ForEach-Object {
                                New-CacheResultObject -ResultType 'ESD' -ResultFullName ([string]$_.FullName) -VolumeMetadata $cacheEntry.VolumeMetadata
                            }
                    }
                }
                break
            }
            'ISO' {
                foreach ($cacheEntry in $cachePaths) {
                    $isoPath = Join-Path -Path $cacheEntry.CachePath -ChildPath 'ISO'
                    if (Test-Path -LiteralPath $isoPath) {
                        Get-ChildItem -LiteralPath $isoPath -Recurse -File -Filter '*.iso' -ErrorAction SilentlyContinue |
                            ForEach-Object {
                                New-CacheResultObject -ResultType 'ISO' -ResultFullName ([string]$_.FullName) -VolumeMetadata $cacheEntry.VolumeMetadata
                            }
                    }
                }
                break
            }
            'DriverPacks' {
                foreach ($cacheEntry in $cachePaths) {
                    $driverPacksPath = Join-Path -Path $cacheEntry.CachePath -ChildPath 'DriverPacks'
                    if (Test-Path -LiteralPath $driverPacksPath) {
                        Get-ChildItem -LiteralPath $driverPacksPath -Recurse -File -ErrorAction SilentlyContinue |
                            Where-Object { $_.Extension -in @('.cab', '.exe', '.msi', '.zip') } |
                            ForEach-Object {
                                New-CacheResultObject -ResultType 'DriverPacks' -ResultFullName ([string]$_.FullName) -VolumeMetadata $cacheEntry.VolumeMetadata
                            }
                    }
                }
                break
            }
            'Drivers' {
                foreach ($cacheEntry in $cachePaths) {
                    $driversPath = Join-Path -Path $cacheEntry.CachePath -ChildPath 'Drivers'
                    if (Test-Path -LiteralPath $driversPath) {
                        Get-ChildItem -LiteralPath $driversPath -Directory -ErrorAction SilentlyContinue |
                            Where-Object {
                                @(Get-ChildItem -LiteralPath $_.FullName -Recurse -File -Filter '*.inf' -ErrorAction SilentlyContinue).Count -gt 0
                            } |
                            ForEach-Object {
                                New-CacheResultObject -ResultType 'Drivers' -ResultFullName ([string]$_.FullName) -VolumeMetadata $cacheEntry.VolumeMetadata
                            }
                    }
                }
                break
            }
            { $_ -in @('ModelDrivers', 'WinPEDrivers') } {
                $driverType = if ($selectedType -eq 'ModelDrivers') { 'ModelDrivers' } else { 'WinPEDrivers' }
                foreach ($cacheEntry in $cachePaths) {
                    foreach ($architecture in 'amd64', 'arm64') {
                        $architectureDriversPath = Join-Path -Path $cacheEntry.CachePath -ChildPath "$($driverType.ToLowerInvariant())-$architecture"
                        if (-not (Test-Path -LiteralPath $architectureDriversPath -PathType Container)) {
                            continue
                        }

                        foreach ($folder in (Get-ChildItem -LiteralPath $architectureDriversPath -Directory -ErrorAction Stop)) {
                            $buildVersion = $null
                            if ($folder.Name -notmatch '^(?<Identity>[^_]+_.+_.+)_(?<Build>\d+\.\d+)$' -or
                                -not [version]::TryParse($Matches.Build, [ref]$buildVersion)) {
                                Write-Warning "[$(Get-Date -format s)] Invalid $driverType folder name: $($folder.FullName)"
                                continue
                            }
                            $modelIdentity = $Matches.Identity
                            $infFiles = @(Get-ChildItem -LiteralPath $folder.FullName -Recurse -File -Filter '*.inf' -ErrorAction Stop)
                            if ($infFiles.Count -eq 0) {
                                continue
                            }

                            $cacheObject = New-CacheResultObject -ResultType $driverType -ResultFullName $folder.FullName -VolumeMetadata $cacheEntry.VolumeMetadata
                            $cacheObject | Add-Member -NotePropertyName OSArchitecture -NotePropertyValue $architecture
                            $cacheObject | Add-Member -NotePropertyName OSBuildVersion -NotePropertyValue $buildVersion.ToString()
                            $cacheObject | Add-Member -NotePropertyName ModelIdentity -NotePropertyValue $modelIdentity
                            $cacheObject
                        }
                    }
                }
                break
            }
            'Profiles' {
                foreach ($cacheEntry in $cachePaths) {
                    $profilesPath = Join-Path -Path $cacheEntry.CachePath -ChildPath 'Profiles'
                    if (Test-Path -LiteralPath $profilesPath) {
                        Get-ChildItem -LiteralPath $profilesPath -Directory -ErrorAction SilentlyContinue |
                            ForEach-Object {
                                New-CacheResultObject -ResultType 'Profiles' -ResultFullName ([string]$_.FullName) -VolumeMetadata $cacheEntry.VolumeMetadata
                            }
                    }
                }
                break
            }
            'WIM' {
                foreach ($cacheEntry in $cachePaths) {
                    $wimPath = Join-Path -Path $cacheEntry.CachePath -ChildPath 'WIM'
                    if (Test-Path -LiteralPath $wimPath) {
                        Get-ChildItem -LiteralPath $wimPath -Recurse -File -Filter '*.wim' -ErrorAction SilentlyContinue |
                            ForEach-Object {
                                New-CacheResultObject -ResultType 'WIM' -ResultFullName ([string]$_.FullName) -VolumeMetadata $cacheEntry.VolumeMetadata
                            }
                    }
                }
                break
            }
        }
    }

    $result = @($result | Sort-Object -Property FullName, Type -Unique | Sort-Object -Property Type, FullName)
    $result | Export-Clixml -Path (Join-Path -Path $env:Temp -ChildPath 'OSDCoreCache.xml') -Force
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Found $($result.Count) path(s)"
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] End"

    return $result
}