Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Easy SFTP (Secure FTP) With C# and PSFTP

0.00/5 (No votes)
3 Feb 2014 1  
SFTP Files using PLINK as a process in C#

Introduction

There are a number of .NET projects out there that allow you to use SFTP, but all of them I've tried are confusing or just don't work. The makers of PuTTY (an open source telnet/SSH/etc client) made a command line app (PSFTP download it here) specifically for people scripting SFTP. Essentially, it's a command line app that takes a few arguements and can run a batch script. The code below is a basic introduction to using it with your C# apps. It generates the batch script automatically and runs PSFTP as a process. For more uses of PSFTP, read the documetation here.

Two catches

  1. You have to accept the SSH certificate from the server you're trying to connect to prior to running the script below or it WILL NOT work, to do this, just use PuTTY or some other SSH client to connect to the server and accept its certificate;
  2. This is ONLY for SFTP! For regular FTP, check out my other post here.

Using the Code

class Program
{
    static void Main(string[] args)
    {
        //Files on the server
        string[] remoteFiles = new string[]
        {
            @"/etc/remote-file1.txt",
            @"/etc/remote-file2.txt",
            @"/etc/remote-file3.txt"
        };
        //Files on your computer
        string[] localFiles = new string[]
        {
            @"C:\local-file1.txt",
            @"C:\local-file2.txt",
            @"C:\local-file3.txt"
        };
        //Other commands (not download/upload)
        string[] commands = new string[]
        {
            @"cd /home",
            @"dir"
        };

        //Create the object and run some commands!
        PSFTP PsftpClient = new PSFTP(@"10.10.10.10", @"root", @"password");
        PsftpClient.Get(remoteFiles, localFiles);
        PsftpClient.Put(remoteFiles, localFiles);
        PsftpClient.SendCommands(commands);

        Console.WriteLine(PsftpClient.Outputs);

        PsftpClient = null;
    }
}  

Here is the actual code. You want to make sure you are 'using' System.Diagnostics.

class PSFTP
{
    private string _Host;
    private string _User;
    private string _Password;

    private string _BatchFilePath = @"C:\batch.txt";
    private string _PsftpPath = @"C:\psftp"; /* Change this to the location 
    		of the PSTFP app.  Do not include the '.exe' file extension. */
    public string Outputs = ""; /* Stores the outputs and errors of PSFTP */

    /* Object Constructor for standard usage */
    public PSFTP(string Host, string User, string Password)
    {
        _Host = Host;
        _User = User;
        _Password = Password;
    }

    /* Object Constructor for Threading */
    /* Specify the commands carefully */
    public PSFTP(string Host, string User, string Password, string[] Commands)
    {
        _Host = Host;
        _User = User;
        _Password = Password;
        GenerateBatchFile(Commands);
    }

    /* Retrieve files from the server */
    public void Get(string[] Remote, string[] Local)
    {
        /* Format the commands */
        string[] Commands = new string[Remote.Count()];

        for (int i = 0; i < Remote.Count(); i++)
        {
            Commands[i] = @"get " + Remote[i] + @" " + Local[i];
        }

        GenerateBatchFile(Commands);

        Run();

        return;
    }

    /* Send files from your computer to the server */
    public void Put(string[] Remote, string[] Local)
    {
        /* Format the commands */
        string[] Commands = new string[Remote.Count()];

        for (int i = 0; i < Remote.Count(); i++)
        {
            Commands[i] = @"put " + Remote[i] + @" " + Local[i];
        }

        GenerateBatchFile(Commands);

        Run();

        return;
    }

    /* Use this to send other SFTP commands (CD, DIR, etc.) */
    public void SendCommands(string[] commands)
    {
        GenerateBatchFile(commands);

        Run();

        return;
    }

    /* Create a text file with a list of commands to be fed into PSFTP */
    private void GenerateBatchFile(string[] Commands)
    {
        try
        {
            StreamWriter batchWriter = new StreamWriter(_BatchFilePath);

            /* Write each command to the batch file */
            for (int i = 0; i < Commands.Count(); i++)
            {
                batchWriter.WriteLine(Commands[i]);
            }

            /* Command to close the connection */
            batchWriter.WriteLine(@"bye");

            batchWriter.Close();
        }
        catch (Exception ex) { Console.WriteLine(ex.ToString()); }

        return;
    }

    /* Run the commands, store the outputs */
    private void Run()
    {
        /* Execute PSFTP as a System.Diagnostics.Process using the supplied login info and generated batch file */
        try
        {
            ProcessStartInfo PsftpStartInfo = new ProcessStartInfo(_PsftpPath, 
            _User + @"@" + _Host + @" -pw " + _Password + @" -batch -be -b " + _BatchFilePath);

            /* Allows redirecting inputs/outputs of PSFTP to your app */
            PsftpStartInfo.RedirectStandardInput = true;
            PsftpStartInfo.RedirectStandardOutput = true;
            PsftpStartInfo.RedirectStandardError = true;
            PsftpStartInfo.UseShellExecute = false;

            Process PsftpProcess = new Process();
            PsftpProcess.StartInfo = PsftpStartInfo;
            PsftpProcess.Start();

            /* Streams for capturing outputs and errors as well as taking ownership of the input */
            StreamReader PsftpOutput = PsftpProcess.StandardOutput;
            StreamReader PsftpError = PsftpProcess.StandardError;
            StreamWriter PsftpInput = PsftpProcess.StandardInput;


            while (!PsftpOutput.EndOfStream)
            {
                try
                {
                    /* This is usefule for commands other than 'put' or 'get' <br />                     and for catching errors. */
                    Outputs += PsftpOutput.ReadLine();
                    Outputs += PsftpError.ReadLine();
                }
                catch (Exception ex) { Console.WriteLine(ex.ToString()); }
            }

            PsftpOutput.Close();
            PsftpError.Close();
            PsftpInput.Close();
            PsftpProcess.WaitForExit();

            PsftpStartInfo = null;
            PsftpProcess = null;
        }
        catch (Exception ex) { Console.WriteLine(ex.ToString()); }

        /* Delete the batch file */
        try
        {
            File.Delete(_BatchFilePath);
        }
        catch (Exception ex) { Console.WriteLine(ex.ToString()); }

        return;
    }
} 

Points of Interest

There's certainly room to add more features depending on your needs. Threading this wouldn't be a difficult task.

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here