Home ProgrammingC# Visual C#: GUI front-end for OpenSSH in Windows

Visual C#: GUI front-end for OpenSSH in Windows

by Kliment Andreev
6.7K views

As of late 2018, Windows 10 and Windows 2019 come up with OpenSSH installed. I had to use OpenSSH in some of the scripts at work, but managing the connections became difficult. So, I created a small .NET program that manages SSH connections. It’s a very simple SSH GUI front-end for OpenSSH. It’s not meant to be a replacement for putty or any other SSH terminal programs.
In case you get an error that your PEM certificate is wide open, change the permissions on that file. Do this from a command prompt, not from a Power Shell prompt.

set key="c:\folder\mykey.pem"
cmd /c icacls %key% /c /t /inheritance:d
cmd /c icacls %key% /c /t /grant %username%:F
cmd /c icacls %key%  /c /t /remove Administrator BUILTIN\Administrators BUILTIN Everyone System Users "Authenticated Users"
cmd /c icacls %key%

Here is the link to the GitHub repo.
Here is a screenshot.

Here is the C# source. Click + to expand.

using System;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;

namespace pusshy
{
    public partial class frmpusshy : Form
    {
        //It holds the name of the header column when a cell is right-clicked
        //Used for hiding columns
        string strColumnHeader; 
        //When a user hits enter, the next selected cell is on the right, not the bottom one
        //It allows horizontal scrolling when typing, not vertical
        protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
        {
            int intColumn = gridHosts.CurrentCell.ColumnIndex;
            int intRow = gridHosts.CurrentCell.RowIndex;
            if (keyData == Keys.Enter)
            {
                if (intColumn == gridHosts.Columns.Count - 1)
                {
                    gridHosts.Rows.Add();
                    gridHosts.CurrentCell = gridHosts[0, intRow + 1];
                }
                else
                {
                    gridHosts.CurrentCell = gridHosts[intColumn + 1, intRow];
                }
                return true;
            }
            else
                return base.ProcessCmdKey(ref msg, keyData);
        }

        public frmpusshy()
        {
            InitializeComponent();
        }

        private void frmpusshy_FormClosed(object sender, FormClosedEventArgs e)
        {
            //Save the current size and position of the window
            //Used to remember these settings when the program is started next time
            Properties.Settings.Default["Location"] = this.Location;
            Properties.Settings.Default["Size"] = this.Size;
            Properties.Settings.Default.Save();
            //The local app data folder where settings and the data will be saved
            var strLocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            //The data is in pusshy.csv file under C:\Users\<username>\AppData\Local\pusshy
            var strFileName = strLocalAppData + "/pusshy/" + "pusshy.csv";
            string strCellValue;
            //Open the file for saving
            StreamWriter csvFileWriter = new StreamWriter(strFileName, false);
            int intColumnCount = gridHosts.ColumnCount - 1;
            int intColCount = gridHosts.Columns.Count;
            //Iterate through the grid and save
            foreach (DataGridViewRow dataRowObject in gridHosts.Rows)
            {
                if (!dataRowObject.IsNewRow)
                {
                    string strDataFromGrid = "";                    
                    for (int i = 0; i <= intColumnCount; i++)
                    {
                        try
                        {
                            strCellValue = dataRowObject.Cells[i].Value.ToString();
                        }
                        //If the cell has no value, replace it with blank string instead of null
                        catch (System.NullReferenceException exception)
                        {
                            strCellValue = "";
                        }
                        //Create a comma separated line
                        if (i != 0)
                        {
                            strDataFromGrid = strDataFromGrid + ',' + strCellValue;
                        }
                        else
                        {
                            strDataFromGrid = strCellValue;
                        }
                    }
                    csvFileWriter.WriteLine(strDataFromGrid);
                }
            }
            csvFileWriter.Flush();
            csvFileWriter.Close();
        }
        //Tag the whole row if there is a password in the password column (column=2). Used to hide password cells
        private void gridHosts_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {            
            if (gridHosts.CurrentRow.Tag != null && gridHosts.CurrentCell.ColumnIndex == 2)
            {
                e.Control.Text = gridHosts.CurrentRow.Tag.ToString();
            }
        }
        //Replace the text in the password cell (column=2) with dots
        private void gridHosts_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 2 && e.Value != null)
            {                
                gridHosts.Rows[e.RowIndex].Tag = e.Value;
                e.Value = new String('\u25CF', e.Value.ToString().Length);
            }
        }
        //Right-click on row header or column header
        private void gridHosts_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                var hit = gridHosts.HitTest(e.X, e.Y);
                var intCurrentColumnIndex = hit.ColumnIndex;
                //If the user right-clicks the column header display this menu
                if ((hit.Type == DataGridViewHitTestType.ColumnHeader))
                {
                    strColumnHeader = gridHosts.Columns[intCurrentColumnIndex].HeaderText;
                    menuRightColumnClick.Show(MousePosition);
                }
                //If the user right-clicks the column header display this menu
                if ((hit.Type == DataGridViewHitTestType.RowHeader))
                {
                    menuRightRowClick.Show(MousePosition);
                }
            }
        }
        //Hide the column that was selected
        private void hideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            gridHosts.Columns[strColumnHeader].Visible = false;
        }       
        //Delete a row
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in gridHosts.SelectedRows)
            {
                try
                {
                    gridHosts.Rows.Remove(row);
                }
                //Can't delete the bottom row. Catch the exception
                catch (InvalidOperationException exception)
                {
                    return;
                }
            }
        }

        private void frmpusshy_Load(object sender, EventArgs e)
        {
            //The local app data folder where settings and the data will be saved
            var strLocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            //The data is in pusshy.csv file under C:\Users\<username>\AppData\Local\pusshy
            var strFileName = strLocalAppData + "/pusshy/" + "pusshy.csv";
            if (!File.Exists(strFileName))
            {
                return;
            }   
            //Clear the grid and load the pusshy.csv file
            gridHosts.Rows.Clear();
            StreamReader fileReader = new StreamReader(strFileName, false);
            int i = 0;
            while (fileReader.Peek() != -1)
            {
                var fileRow = fileReader.ReadLine();
                var fileDataField = fileRow.Split(',');
                gridHosts.Rows.Add(fileDataField);
                //var rd = fileDataField[2];                
                i++;
            }
            fileReader.Dispose();
            fileReader.Close();
            //Change the size and the position of the application on load
            //With the settings that were saved last time the app was used
            this.Location = Properties.Settings.Default.Location;
            this.Size = Properties.Settings.Default.Size;
        }
        //When the user chooses Show All, all hidden columns will become visible
        private void showAllToolStripMenuItem_Click(object sender, EventArgs e)
        {            
            foreach (DataGridViewColumn column in gridHosts.Columns)
            {
                string strHeaderCaptionText = column.HeaderText;
                gridHosts.Columns[strHeaderCaptionText].Visible = true;
            }                    
        }
        //When the user double-clicks a cell, launch the terminal
        private void gridHosts_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            string strCommand = "";
            int intRowIndex = gridHosts.CurrentCell.RowIndex;  
            //Get all values from the row
            string strHost = gridHosts.Rows[intRowIndex].Cells[0].Value.ToString();
            string strLogin = gridHosts.Rows[intRowIndex].Cells[1].Value.ToString();
            string strPwd = gridHosts.Rows[intRowIndex].Cells[2].Value.ToString();
            string strCert = gridHosts.Rows[intRowIndex].Cells[3].Value.ToString();
            //If the password cell is empty, start the terminal with certificate
            if (strPwd == "")
            {
                strCommand = "\"C:/windows/sysnative/OpenSSH/ssh.exe\" -l " + strLogin + " " + "-i " + strCert + " " + strHost;
            } else
            //Or without password
            {
                strCommand = "\"C:/windows/sysnative/OpenSSH/ssh.exe\" -l " + strLogin + " " + strHost;
            }
            Process.Start("powershell.exe", strCommand);            
        }
    }
}

Related Articles

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More