private/BootMedia/Steps/Step-BootImageAppAzCopy.ps1

#Requires -PSEdition Core

function Step-BootImageAppAzCopy {
    <#
    .SYNOPSIS
        Downloads, caches, and injects AzCopy into the mounted WinPE image.
 
    .NOTES
        Author: David Segura
        Version: 0.1.0
    #>

    [CmdletBinding()]
    param ()

    $Architecture = $global:BuildMedia.Architecture
    $MountPath = $global:BuildMedia.MountPath
    $WinPEAppsPath = Join-Path $Script:OSDeployCorePath 'cache' 'winpe-apps'
    $azcopyConfig = $global:OSDeployModule.BootImage.winpeapps.azcopy

    $CacheAzCopy = Join-Path $WinPEAppsPath 'microsoft-azcopy'

    if (-not (Test-Path -Path $CacheAzCopy)) {
        Write-OSDeployCoreProgress "Creating AzCopy cache: $CacheAzCopy"
        New-Item -Path $CacheAzCopy -ItemType Directory -Force | Out-Null
    }
    else {
        Write-OSDeployCoreProgress "Using AzCopy cache: $CacheAzCopy"
    }

    # Download amd64 version
    if (-not (Test-Path "$CacheAzCopy\amd64")) {
        $Uri = $azcopyConfig.amd64
        try {
            $DownloadUri = (Invoke-WebRequest -Uri $Uri -Method Head -ErrorAction SilentlyContinue).BaseResponse.RequestMessage.RequestUri.AbsoluteUri
            if ($DownloadUri) {
                $FileName = if ($DownloadUri -match 'filename%3D([^&]+)') { [System.Uri]::UnescapeDataString($Matches[1]) } else { Split-Path $DownloadUri -Leaf }
                if (-not (Test-Path "$CacheAzCopy\$FileName")) {
                    Write-OSDeployCoreProgress "Downloading AzCopy amd64: $FileName"
                    $downloadPath = Join-Path $CacheAzCopy $FileName
                    if (Get-Command 'curl.exe' -ErrorAction SilentlyContinue) {
                        & curl.exe --silent --location --output $downloadPath $DownloadUri
                    }
                    else {
                        Invoke-WebRequest -UseBasicParsing -Uri $DownloadUri -OutFile $downloadPath
                    }
                    Expand-Archive -Path $downloadPath -DestinationPath "$CacheAzCopy\amd64" -Force
                }
            }
        }
        catch {
            Write-Warning "Failed to download AzCopy amd64: $_"
        }
    }

    # Download arm64 version
    if (-not (Test-Path "$CacheAzCopy\arm64")) {
        $Uri = $azcopyConfig.arm64
        try {
            $DownloadUri = (Invoke-WebRequest -Uri $Uri -Method Head -ErrorAction SilentlyContinue).BaseResponse.RequestMessage.RequestUri.AbsoluteUri
            if ($DownloadUri) {
                $FileName = if ($DownloadUri -match 'filename%3D([^&]+)') { [System.Uri]::UnescapeDataString($Matches[1]) } else { Split-Path $DownloadUri -Leaf }
                if (-not (Test-Path "$CacheAzCopy\$FileName")) {
                    Write-OSDeployCoreProgress "Downloading AzCopy arm64: $FileName"
                    $downloadPath = Join-Path $CacheAzCopy $FileName
                    if (Get-Command 'curl.exe' -ErrorAction SilentlyContinue) {
                        & curl.exe --silent --location --output $downloadPath $DownloadUri
                    }
                    else {
                        Invoke-WebRequest -UseBasicParsing -Uri $DownloadUri -OutFile $downloadPath
                    }
                    Expand-Archive -Path $downloadPath -DestinationPath "$CacheAzCopy\arm64" -Force
                }
            }
        }
        catch {
            Write-Warning "Failed to download AzCopy arm64: $_"
        }
    }

    # Copy AzCopy to WinPE
    Get-ChildItem -Path "$CacheAzCopy\$Architecture" -Recurse -Include 'AzCopy.exe' -ErrorAction SilentlyContinue | ForEach-Object {
        Write-OSDeployCoreProgress "Injecting AzCopy.exe into WinPE"
        Copy-Item $_.FullName -Destination "$MountPath\Windows\System32" -Force
        $global:BuildMedia.InstalledApps += 'AzCopy'
    }
}