Using WinSCP .NET Assembly from PowerShell

Advertisement

About PowerShell

PowerShell is Microsoft’s task automation framework, consisting of a command-line shell and associated scripting language built on .NET.

Windows PowerShell (powershell.exe) is built into Windows 7 and newer; and is optionally available for Windows 98 SP2 and newer.1 It uses .NET Framework. Its successor, PowerShell (pwsh.exe), previously known as PowerShell Core, aka PowerShell 6/7, is cross-platform and can be optionally installed in Windows. It uses .NET (previously known as .NET Core).

PowerShell scripts can be directly executed, they do not need to be compiled first.

PowerShell Scripting

From WinSCP scripting perspective, an important aspect of PowerShell is its ability to run simple, yet powerful, scripts that can make use of functionality exposed by WinSCP .NET assembly.

Windows PowerShell’s powershell.exe is located in %WINDIR%\System32\WindowsPowershell\v1.0.2 Typically you run powershell.exe with -File argument followed by path to your PowerShell script. The script file needs to have .ps1 extension:

powershell.exe -File upload.ps1

PowerShell (Core)’s pwsh.exe installs into C:\Program Files\PowerShell\<version>.

Note that by default, executing PowerShell scripts is disabled. To override that, you can either lift the restriction by typing using Set-ExecutionPolicy cmdlet on PowerShell administrator console:3

Set-ExecutionPolicy Unrestricted

Advertisement

or use -ExecutionPolicy argument for every script run:

powershell.exe -ExecutionPolicy Unrestricted -File upload.ps1 

Installing the Assembly

First, you need to install the WinSCP .NET assembly. In most cases, all you need to do is download the WinSCP-X.X.X-Automation.zip package4 and extract it along with your PowerShell script.5

The version of WinSCPnet.dll in the root of the package is the .NET Framework build of the assembly. It can be used with Windows PowerShell only. With PowerShell (Core) 6/7, you have to use the .NET Standard build of the assembly, which is located in the netstandard2.0 subfolder.

For specific cases, read full instructions to installing the WinSCP .NET assembly.

Using from PowerShell

You use WinSCP .NET assembly from PowerShell as any other .NET assembly.

Though there are some less known techniques and peculiarities that you may need to use, which are described in following sections.

Loading Assembly

PowerShell script needs to load the assembly before it can use classes the assembly exposes. To load assembly use Add-Type cmdlet.6

Add-Type -Path "WinSCPnet.dll"

Had you need to run the script from other directory, you need to specify a full path to the assembly. You can derive the path from the script file path using $PSScriptRoot automatic variable:7

Add-Type -Path (Join-Path $PSScriptRoot "WinSCPnet.dll")

If you are writing a script that you plan to use as a WinSCP extension (a custom command), you can use the copy of the assembly installed with WinSCP. In that case you can use the WINSCP_PATH environment variable to resolve the path to the assembly. To allow the script run even outside of WinSCP, you should fall back to the $PSScriptRoot approach (as above), if the variable is not defined:

$assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }
Add-Type -Path (Join-Path $assemblyPath "WinSCPnet.dll")

Accessing Enumeration Values

Enumeration values are accessed using static field syntax [Namespace.Type]::Member, for example [WinSCP.Protocol]::Sftp.

Advertisement

Event Handlers

The Session class exposes several events.

If you need to make use of these events:

  • Define event handling function;
  • Associate the event handling function with an instance of Session class using .add_Event method, where Event is a name of the event.8
  • If you need to disassociate the event handling function later, use .remove_Event method.

See following code snippet:

# Event handling function
function FileTransferred
{
    param($e)
 
    if ($e.Error -eq $Null)
    {
        Write-Host "Transfer of $($e.FileName) succeeded"
    }
    else
    {
        Write-Host "Transfer of $($e.FileName) failed: $($e.Error)"
    }
}
 
...
 
# Subscribe to the event
$session.add_FileTransferred( { FileTransferred($_) } )

PowerShell Module

There is a third-party PowerShell module, WinSCP PowerShell Wrapper, that provides a cmdlet interface on top of the .NET assembly.

Example:

# Set credentials to a PSCredential Object.
$credential = Get-Credential
# Create a WinSCP Session.
$session = New-WinSCPSession -Hostname "example.com" -Credential $credential -SshHostKeyFingerprint "ssh-rsa 2048 xxxxxxxxxxx..."
# Using the WinSCPSession, download the file from the remote host to the local host.
Receive-WinSCPItem -WinSCPSession $session -Path "/home/user/file.txt" -Destination "C:\download\"
# Remove the WinSCPSession after completion.
Remove-WinSCPSession -WinSCPSession $session

Advertisement

Accomplish the same task with one line of code:

# Piping the WinSCPSession into the Receive-WinSCPItem auto disposes the WinSCP.Session object after completion.
New-WinSCPSession -Hostname "example.com" -Credential (Get-Credential) -SshHostKeyFingerprint "ssh-rsa 2048 xxxxxxxxxxx...") | 
     Receive-WinSCPItem -Path "/home/user/file.txt" -Destination "C:\download\"

Example

This example is functionally equivalent to overall C# example for WinSCP .NET assembly.

There are also other PowerShell examples.

try
{
    # Load WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
 
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Sftp
        HostName = "example.com"
        UserName = "user"
        Password = "mypassword"
        SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx..."
    }
 
    $session = New-Object WinSCP.Session
 
    try
    {
        # Connect
        $session.Open($sessionOptions)
 
        # Upload files
        $transferOptions = New-Object WinSCP.TransferOptions
        $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
 
        $transferResult =
            $session.PutFiles("d:\toupload\*", "/home/user/", $False, $transferOptions)
 
        # Throw on any error
        $transferResult.Check()
 
        # Print results
        foreach ($transfer in $transferResult.Transfers)
        {
            Write-Host "Upload of $($transfer.FileName) succeeded"
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
 
    exit 0
}
catch
{
    Write-Host "Error: $($_.Exception.Message)"
    exit 1
}

Advertisement

Converting Script to PowerShell Code

When you are considering converting your script to code that uses WinSCP .NET assembly, PowerShell, thanks to its ubiquity, can be a good choice, particularly, when you do not have your own preferred language that supports .NET.

  1. The text is partially copied from Wikipedia article on PowerShell. The text is licensed under GNU Free Documentation License.Back
  2. It’s v1.0, disregarding what version you actually use.Back
  3. Run powershell.exe as Administrator to get PowerShell console.Back
  4. In some cases, the downloaded executables need to be unblocked.Back
  5. Generally you only need WinSCPnet.dll and WinSCP.exe.Back
  6. In PowerShell 1.0, use System.Reflection.Assembly.LoadFrom method.Back
  7. In PowerShell 2.0, use Add-Type -Path (Join-Path (Split-Path $script:MyInvocation.MyCommand.Path) "WinSCPnet.dll")Back
  8. Avoid using Register-ObjectEvent cmdlet, as it introduces threading problems and possible crashes.Back

Last modified: by martin