functions/Copy-FilesFromContainerImage.ps1
# <copyright file="Copy-FilesFromContainerImage.ps1" company="Endjin Limited"> # Copyright (c) Endjin Limited. All rights reserved. # </copyright> function Copy-FilesFromContainerImage { <# .SYNOPSIS Copies files from a specified container image to a destination path on the local system. .DESCRIPTION Copies one or more files from a given container image and to a specified destination path on the host system. It has two modes of operation: - 'Files' mode: copies specific files from the container image to the destination path, using the same file copy semantics as the `Copy-Item` cmdlet. - 'Archive' mode: copies the entire container filesystem as a tarball to the destination path. .PARAMETER SourceImageName The full repository, name and tag name of the container image from which the root filesystem will be used to create the disk image. .PARAMETER DestinationFolderPath The base directory where the specified files will be saved. .EXAMPLE Copy-FilesFromContainerImage -SourceImageName "mycontainer:latest" ` -DestinationFolderPath "C:\Images" ` -AllFilesAsTar This command copies a tarball containing all files from the `mycontainer:latest` container to `C:\Images\mycontainer-latest.tar` .EXAMPLE Copy-FilesFromContainerImage -SourceImageName "mycontainer:latest" ` -DestinationFolderPath "C:\Images" ` -Filter *.bin ` -Recurse This command recursively copies all files matching the `*.bin` filter from the `mycontainer:latest` docker image to `C:\Images`. .NOTES This function requires Docker to be installed and running on the host system. #> [CmdletBinding(DefaultParameterSetName = 'Files')] param ( [Parameter(Mandatory=$true)] [string] $SourceImageName, [Parameter(Mandatory=$true)] [string] $DestinationFolderPath, [Parameter(Mandatory=$true, ParameterSetName="Archive")] [switch] $AllFilesAsTar, [Parameter(ParameterSetName="Files")] [string] $Filter, [Parameter(ParameterSetName="Files")] [string[]] $Include, [Parameter(ParameterSetName="Files")] [string[]] $Exclude, [Parameter()] [switch] $OverwriteDestination, [Parameter(ParameterSetName="Files")] [switch] $Recurse, [Parameter()] [switch] $AlwaysPull, [Parameter()] [switch] $PassThru, [Parameter()] [string] $ContainerCommand = "/bin/sh" ) @( "docker" "tar" ) | ForEach-Object { if (!(Get-Command $_ -ErrorAction Ignore)) { throw "The '$_' command is required to run this function" } } $existingImage = & docker images --format "{{.Repository}}:{{.Tag}}" | Where-Object { $_ -eq $SourceImageName } if (!$existingImage -or $AlwaysPull) { Write-Host "Pulling image: $SourceImageName" & docker pull $SourceImageName | Write-Verbose } $tmpContainerName = (New-Guid).Guid $containerTarPath = Join-Path ([IO.Path]::GetTempPath()) "$tmpContainerName.tar" $tmpContainerExtractPath = Join-Path ([IO.Path]::GetTempPath()) "$tmpContainerName-extract" New-Item -ItemType Directory -Path $tmpContainerExtractPath -Force:$OverwriteDestination | Out-Null # Ensure errors from external tools are propagated to the script - this overridden # value will fall out of scope when the function completes $PSNativeCommandUseErrorActionPreference = $true # Create an instance of the container image & docker create --name $tmpContainerName $SourceImageName $ContainerCommand | Out-Null try { # Extract filesystem from container instance as a tarball Write-Host "Exporting container filesystem to tarball..." & docker export $tmpContainerName -o $containerTarPath | Write-Verbose $splat = @{ Destination = $DestinationFolderPath Force = $OverwriteDestination PassThru = $PassThru Verbose = $VerbosePreference } switch ($PSCmdlet.ParameterSetName) { 'Files' { Write-Host "Copying specified files from container filesystem" # Unpack files from the tarball & tar -xf $containerTarPath -C $tmpContainerExtractPath | Write-Verbose # Copying required files $splat += @{ Path = (Join-Path $tmpContainerExtractPath ([IO.Path]::DirectorySeparatorChar) "*") Recurse = $Recurse } if ($Filter) { $splat.Filter = $Filter } if ($Include) { $splat.Include = $Include } if ($Exclude) { $splat.Exclude = $Exclude } } 'Archive' { Write-Host "Copying tarball of entire container filesystem" $splat += @{ Path = $containerTarPath } } } $copiedFiles = Copy-Item @splat } finally { # Clean-up temporary resources if (Test-Path $containerTarPath) { Remove-Item $containerTarPath -Force } if (Test-Path $containerTarPath) { Remove-Item $tmpContainerExtractPath -Force } & docker rm -f $tmpContainerName | Write-Verbose } if ($PassThru) { return $copiedFiles } } |