Click here to Skip to main content
15,881,803 members
Articles / DevOps / Automation
Tip/Trick

Easy SFTP (Secure FTP) With C# and PSFTP

Rate me:
Please Sign up or sign in to vote.
4.60/5 (7 votes)
3 Feb 2014CPOL1 min read 63.6K   25   2
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

C#
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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionPlease explain your post Pin
Ramesh.G>K>R1-Sep-14 22:30
Ramesh.G>K>R1-Sep-14 22:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.