Pack files to ZIP archive and upload it

The following script uses WinSCP .NET assembly from a PowerShell script. If you have another preferred language, you can easily translate it.

The script is distributed in WinSCP installer as a WinSCP extension.

To use a different archive format than ZIP, you can install 7-Zip, add configure the extension to use it.

Advertisement

To run the script manually use:

powershell.exe -File "ZipUpload.ps1" -sessionUrl "sftp://username:password;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/" -remotePath "/remote/path" -archiveName "archive.zip" file1.dat file2.dat

For opposite functionality, use extension Archive remote files to ZIP archive, download it, and optionally extract it.

# @name         &ZIP and Upload...
# @command      powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" ^
#                   -sessionUrl "!E" -remotePath "!/" -archiveName "%ArchiveName%" ^
#                   -refresh -pause -sessionLogPath "%SessionLogPath%" ^
#                   %Use7zip% -path7zip "%Path7zip%" -archive7zip %Archive7zip% !&
# @description  Packs the selected files to a ZIP archive and uploads it
# @flag         ApplyToDirectories
# @version      10
# @homepage     https://winscp.net/eng/docs/library_example_zip_and_upload
# @require      WinSCP 5.16
# @require      .NET 4.5
# @option       ArchiveName -run textbox "&Archive name:" "archive"
# @option       - -config -run group "7-zip"
# @option         Use7zip -config -run checkbox "Use &7-zip" "" -use7zip
# @option         Archive7zip -config -run dropdownlist "Archive &type (with 7-zip):" ^
#                     zip zip 7z xz gzip bzip2 tar
# @option         Path7zip -config file "7-zip &path (7z.exe/7za.exe):" ^
#                     "C:\Program Files\7-Zip\7z.exe"
# @option       - -config group "Logging"
# @option         SessionLogPath -config sessionlogfile
# @optionspage  https://winscp.net/eng/docs/library_example_zip_and_upload#options
 
param (
    # Use Generate Session URL function to obtain a value for -sessionUrl parameter.
    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/",
    [Parameter(Mandatory = $True)]
    $remotePath,
    [Switch]
    $pause,
    [Switch]
    $refresh,
    [Switch]
    $use7Zip,
    # The 7z.exe can be replaced with portable 7za.exe
    $path7zip = "C:\Program Files\7-Zip\7z.exe",
    $archive7zip = "zip",
    [Parameter(Mandatory = $True)]
    $archiveName,
    $sessionLogPath = $Null,
    [Parameter(Mandatory = $True, ValueFromRemainingArguments = $True, Position = 0)]
    $localPaths
)
 
try
{
    if ($use7Zip)
    {
        $archiveName += "." + $archive7zip
    }
    else
    {
        $archiveName += ".zip"
    }
 
    Write-Host "Archiving $($localPaths.Count) files to archive $archiveName..."
    
    $archivePath = Join-Path ([System.IO.Path]::GetTempPath()) $archiveName
 
    if (Test-Path $archivePath)
    {
        Remove-Item $archivePath
    }
 
    # Using 7-Zip one can create also other archive formats, not just ZIP
    if ($use7Zip)
    {
        # Create archive
        & "$path7zip" a "-t$archive7zip" $archivePath $localPaths
 
        if ($LASTEXITCODE -gt 0)
        {
            throw "Archiving failed."
        }
    }
    else
    {
        if ($PSVersionTable.PSVersion.Major -lt 3)
        {
            throw ("PowerShell 3.0 and newer is required." +
                   "Please, upgrade PowerShell. Or try using the 7-zip mode instead.")
        }
 
        Add-Type -AssemblyName "System.IO.Compression"
        Add-Type -AssemblyName "System.IO.Compression.FileSystem"
 
        $zip =
            [System.IO.Compression.ZipFile]::Open(
                $archivePath, [System.IO.Compression.ZipArchiveMode]::Create)
 
        # Replace with Compress-Archive once PowerShell 5.0 is widespread
 
        foreach ($localPath in $localPaths)
        {
            $parentPath = Split-Path -Parent (Resolve-Path $localPath)
            if ($parentPath[-1] -ne "\")
            {
                $parentPath += "\";
            }
 
            if (Test-Path $localPath -PathType Leaf)
            {
                $files = $localPath
            }
            else
            {
                $files =
                    Get-ChildItem $localPath -Recurse -File |
                    Select-Object -ExpandProperty FullName
            }
 
            foreach ($file in $files)
            {
                $entryName = $file.Replace($parentPath, "")
                Write-Host "Adding $entryName..."
                [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile(
                    $zip, $file, $entryName) | Out-Null
            }
        }
 
        $zip.Dispose()
    }
 
    Write-Host "Archive $archiveName created, uploading..."
 
    # Load WinSCP .NET assembly
    $assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }
    Add-Type -Path (Join-Path $assemblyPath "WinSCPnet.dll")
 
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.ParseUrl($sessionUrl)
 
    $session = New-Object WinSCP.Session
 
    try
    {
        $session.SessionLogPath = $sessionLogPath
 
        # Connect
        $session.Open($sessionOptions)
 
        $session.PutFileToDirectory($archivePath, $remotePath) | Out-Null
 
        Write-Host "Archive $archiveName uploaded."
 
        # Refresh the remote directory in WinSCP GUI, if -refresh switch was used
        if ($refresh)
        {
            Write-Host "Reloading remote directory..."
            & "$env:WINSCP_PATH\WinSCP.exe" "$sessionUrl" /refresh "$remotePath"
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
 
    Remove-Item $archivePath
    $result = 0
}
catch
{
    Write-Host "Error: $($_.Exception.Message)"
    $result = 1
}
 
# Pause if -pause switch was used
if ($pause)
{
    Write-Host "Press any key to exit..."
    [System.Console]::ReadKey() | Out-Null
}
 
exit $result

Advertisement

Options

In the Archive name enter a name of the archive (without extension) to create. The option is available when executing the extension only.

When the Use 7-zip is not checked, the extension uses a native .NET framework implementation for a ZIP compression. In this mode, the extension has no additional dependency. Particularly, if you want to use a different archive type, check the Use 7-zip and install the 7-Zip.

When using 7-Zip, you can use the Archive type to select the archive type to create.

Use the 7-zip path to select an alternative path to the 7z.exe or 7za.exe, particularly if you are using a portable version. The option is available on the Preferences dialog only.

In the Session log file, you can specify a path to a session log file (for uploading). The option is available on the Preferences dialog only.

In the Keyboard shortcut, you can specify a keyboard shortcut for the extension. The option is available on the Preferences dialog only.

Last modified: by martin