Posh-SSH: Open Source SSH PowerShell Module
What
Posh-SSH is a PowerShell 3.0 or newer module for automating tasks against system using the SSH protocol. The module supports only a subset of the capabilities that the different SSH RFCs http://en.wikipedia.org/wiki/Secure_Shell define but it allows for:
- Establish SSH and SFTP sessions using credentials or OpenSSH keys.
- Connecting through SOCKS and HTTP proxies for both SSH and SFTP sessions.
- Execution of commands in a remote host using SSH Exec command.
- Uploading and downloading of files using SCP and SFTP.
From the SSH standards it supports the following:
- Supports DIFFIE-HELLMAN-GROUP-EXCHANGE-SHA256, DIFFIE-HELLMAN-GROUP-EXCHANGE-SHA1, DIFFIE-HELLMAN-GROUP14-SHA1 and DIFFIE-HELLMAN-GROUP1-SHA1 key exchange methods.
- Supports 3DES-cbc, AES128-CBC, AES192-CBC, AES256-CBC, AES128-CTR, AES192-CTR, AES256-CTR, BlowFish-CBC, CAST128-CBC, ARCFour and TwoFish encryptions.
- Supports HMAC-MD5, HMAC-SHA1, HMAC-RIPEMD160, HMAC-SHA2-256, HMAC-SHA2-256-96, HMAC-MD5-96 and HMAC-SHA1-96 hashing algorithms.
- Supports public key, password, and keyboard-interactive authentication methods
- Supports RSA and DSA private key
- Supports DES-EDE3-CBC, DES-EDE3-CFB, DES-CBC, AES-128-CBC, AES-192-CBC and AES-256-CBC algorithms for private key encryption
- Supports SOCKS4, SOCKS5 and HTTP proxy
Why
I wrote the Posh-SSH module for automating testing of code I wrote in Ruby, Python and other languages in a lab environments where the code runs in a variety of systems than ranged from BSD Linux, OS X and Windows systems where I needed to only execute a series of commands and get the output. I knew I could do this with Python- or Ruby-based great SSH libraries but I took it as a challenge to do it in PowerShell. I found the SSHT.NET library in CodePlex http://sshnet.codeplex.com/ and just started implementing the code in PowerShell. Some of the tasks required the interaction with .NET events and I decided to manage those in C# since examples where already present. It was an interesting experience in my journey of learning how to write a PowerShell module in C#. Posh-SSH was born out of my own technical needs and the opportunity to learn new things.
Install
The module is hosted in GitHub at https://github.com/darkoperator/Posh-SSH; all source code for the cmdlets and for the module is available there and it is licensed under the BSD 3-Clause License. The module requires PowerShell 3.0 and .NET Framework 4.0. The quickest way to install the module is by running:
iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev")
This will download the latest version of Posh-SSH and install it in the user’s profile. Once it finishes downloading and copying the module to the right place, it will list the commands available:
Connecting
The way the module works is by establishing sessions to each of the hosts we want to run against. By allowing multiple sessions at once it allows me to control and automate tasks against more than one hosts and not have to re-login to each one. The command to create a new session is New-SSHSession
PS> help New-SSHSession
NAME
New-SSHSession
SYNOPSIS
Creates an SSH Session against a SSH Server
SYNTAX
New-SSHSession [-ComputerName] <String[]> [-Credential] <PSCredential> [-Port <Int32>] [-ProxyServer <String>] [-ProxyPort <Int32>] [-ProxyCredential <PSCredential>] [-ProxyType <String>]
[-ConnectionTimeOut <Int32>] [-KeepAliveInterval <Int32>] [-AcceptKey [<Boolean>]] [-PipelineVariable <String>] [<CommonParameters>]
New-SSHSession [-ComputerName] <String[]> [-Credential] <PSCredential> [-Port <Int32>] [-ProxyServer <String>] [-ProxyPort <Int32>] [-ProxyCredential <PSCredential>] [-ProxyType <String>]
[-KeyFile <String>] [-ConnectionTimeOut <Int32>] [-KeepAliveInterval <Int32>] [-AcceptKey [<Boolean>]] [-PipelineVariable <String>] [<CommonParameters>]
DESCRIPTION
Creates an SSH Session against a remote server. The command supports creating connection thru a Proxy and allows for authentication to the server using username and password. If a key file is
specified the command will use the password in the credentials parameter as the paraphrase of the key.
RELATED LINKS
REMARKS
To see the examples, type: "get-help New-SSHSession -examples".
For more information, type: "get-help New-SSHSession -detailed".
For technical information, type: "get-help New-SSHSession -full".
When we establish a new session for the first time it will check SSH server certificate fingerprint and IP address combination to those saved in HKEY_CURRENT_USER\Software\PoshSSH registry key; if there is a mismatch it will generate an error that the fingerprint did not match and if it is not present it will show the fingerprint and ask if you want to trust or not the host before connecting:
PS> New-SSHSession -ComputerName "192.168.1.191" -Credential (Get-Credential carlos)
Server SSH Fingerprint
Do you want to trust the fingerprint 62:ef:96:b6:f8:a9:6c:7c:34:29:e6:d6:ba:59:ad:2f
[] Y [] N [?] Help (default is "N"): Y
Index Host Connected
----- ---- ---------
0 192.168.1.191 True
We can see all the hosts we trust using the Get-SSHTrustedHost command and one can remove hosts from the trusts list using Remove-SSHTrustedHost:
PS> Get-SSHTrustedHost | fl
SSHHost : 192.168.1.191
Fingerprint : 62:ef:96:b6:f8:a9:6c:7c:34:29:e6:d6:ba:59:ad:2f
When the session is created, we can look at the session using the Get-SSHSession command
PS> Get-SSHSession | fl
Connected : True
Index : 0
Host : 192.168.1.191
Session : Renci.SshNet.SshClient
Each session has the Index property that can be used with other commands or the object that is returned.
To disconnect from the hosts we use the Remove-SSHSession
PS> Remove-SSHSession -Index 0 -Verbose
VERBOSE: 0
VERBOSE: Removing session 0
True
VERBOSE: Session 0 Removed
Executing Command
We can execute commands against a session or sessions using the Invoke-SSHCommand command. When a command is executed an object representing the results of the execution is returned. When executed it instantiates on the system a new instance of the default shell configured on the system, executes the command and returns an object and the exit status of the last command executed.
PS> Invoke-SSHCommand -Index 0 -Command "uname -a"
Host : 192.168.1.191
Output : Linux testdebian7 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux
ExitStatus : 0
In the case of Linux/Unix systems when the command string is given to the shell, the instance is closed so it will retain the state because the shell instance is closed after each execution.
PS> Invoke-SSHCommand -Index 0 -Command "pwd"
Host : 192.168.1.191
Output : /home/carlos
ExitStatus : 0
PS> Invoke-SSHCommand -Index 0 -Command "cd /"
Host : 192.168.1.191
Output :
ExitStatus : 0
PS> Invoke-SSHCommand -Index 0 -Command "pwd"
Host : 192.168.1.191
Output : /home/carlos
ExitStatus : 0
But in the case of Linux or Unix we can chain command with the shell command terminator and have the shell run them.
PS C:\> Invoke-SSHCommand -Index 0 -Command "uname -a; cd /; pwd; ls -l"
Host : 192.168.1.191
Output : Linux testdebian7 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux
/
total 88
drwxr-xr-x 2 root root 4096 Dec 17 2013 bin
drwxr-xr-x 3 root root 4096 Dec 17 2013 boot
drwxr-xr-x 13 root root 3200 Jun 28 11:16 dev
drwxr-xr-x 133 root root 12288 Jun 28 11:16 etc
drwxr-xr-x 3 root root 4096 Dec 17 2013 home
lrwxrwxrwx 1 root root 30 Dec 17 2013 initrd.img -> /boot/initrd.img-3.2.0-4-amd64
drwxr-xr-x 15 root root 4096 Dec 17 2013 lib
drwxr-xr-x 2 root root 4096 Dec 17 2013 lib64
drwx------ 2 root root 16384 Dec 17 2013 lost+found
drwxr-xr-x 4 root root 4096 Oct 13 2013 media
drwxr-xr-x 2 root root 4096 Sep 22 2013 mnt
drwxr-xr-x 2 root root 4096 Oct 13 2013 opt
dr-xr-xr-x 105 root root 0 Jun 28 11:15 proc
drwx------ 3 root root 4096 Dec 17 2013 root
drwxr-xr-x 19 root root 880 Jun 28 11:16 run
drwxr-xr-x 2 root root 4096 Dec 17 2013 sbin
drwxr-xr-x 2 root root 4096 Jun 10 2012 selinux
drwxr-xr-x 2 root root 4096 Oct 13 2013 srv
drwxr-xr-x 13 root root 0 Jun 28 11:15 sys
drwxrwxrwt 6 root root 4096 Jun 28 14:17 tmp
drwxr-xr-x 10 root root 4096 Dec 17 2013 usr
drwxr-xr-x 12 root root 4096 Dec 17 2013 var
lrwxrwxrwx 1 root root 26 Dec 17 2013 vmlinuz -> boot/vmlinuz-3.2.0-4-amd64
ExitStatus : 0
This will work with Unix, Linux and even Windows systems running SSH.
One special case is with Cisco equipment where after execution of the command the Cisco equipment terminated the connection. In this case we can create a console using the SSH session object. When we create the console, it reruns a console stream object to which we can write commands we want to execute, terminating them with e new line and then read the output that was generated by reading the stream.
PS> $session = Get-SSHSession -Index 1
PS> $stream = $session.Session.CreateShellStream("dumb", 0, 0, 0, 0, 1000)
PS> $stream.Write("show ver`n")
PS> $stream.Read()
TSGAP01#show ver
Cisco IOS Software, C1240 Software (C1240-K9W7-M), Version 12.3(8)JA, RELEASE SOFTWARE (fc2)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2006 by Cisco Systems, Inc.
Compiled Mon 27-Feb-06 09:17 by ssearch
ROM: Bootstrap program is C1240 boot loader
BOOTLDR: C1240 Boot Loader (C1240-BOOT-M) Version 12.3(7)JA1, RELEASE SOFTWARE (fc1)
TSGAP01 uptime is 2 minutes
System returned to ROM by power-on
System image file is "flash:/c1240-k9w7-mx.123-8.JA/c1240-k9w7-mx.123-8.JA"
This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.
--More--
PS> $stream.Write("`n")
PS> $stream.Read()
TSGAP01#
Uploading and Downloading Files with SCP
The module also provides SCP commands for uploading and downloading files. SCP works by establishing a connection and copying or downloading the file specified depending on the action selected.
For uploading a file we use the Set-SCPFile cmdlet. We need to specify a server, credentials, a local file that we want to upload, and the full path and name of the full path of the destination file.
PS C:\> Set-SCPFile -LocalFile .\Downloads\VMware-PowerCLI-5.5.0-1671586.exe -RemoteFile "/tmp/powercliinstaller.exe" -ComputerName 192.168.10.3 -Credential (Get-Credential root)
The cmdlet provides progress information about the uploaded bytes.
To download a file the process is similar, but we use the Get-SCPFile cmdlet.
PS C:\> Get-SCPFile -LocalFile .\Downloads\VMware-PowerCLI.exe -RemoteFile "/tmp/powercliinstaller.exe" -ComputerName 192.168.10.3 -Credential (Get-Credential root)
We can also do the same with folder using Get-SCPFolder and Set-SCPFolder. The cmdlet will upload all files recursively.
Using SFTP
The module also provides SFTP support. The SFTP commands also work with sessions. To create a SFTP session we use the New-SFTPSession cmdlet. It uses the same list of trusted hosts as the one for SSH sessions.
PS> New-SFTPSession -ComputerName 192.168.10.3 -Credential (Get-Credential root) -Verbose | fl
VERBOSE: Using Username and Password authentication for connection.
VERBOSE: Connecting to 192.168.10.3 with user root
Connected : True
Index : 0
Host : 192.168.10.3
Session : Renci.SshNet.SftpClient
Just like with SSH commands, SFTP commands use the index of the session or the session object itself to specify a session. Use the Get-SFTPSession command to get all SFTP sessions or a specified one.
PS> Get-SFTPSession | fl
Connected : True
Index : 0
Host : 192.168.10.3
Session : Renci.SshNet.SftpClient
One big difference between SSH and SFTP sessions is that the SFTP session is just like FTP. A stateful one where we can change directory paths and the session remains on that location. We can get our current location on the system using the Get-SFTPCurrentDirectory command and we can change location using Set-SFTPDirectoryPath cmdlet.
PS> Get-SFTPCurrentDirectory -Index 0
/root
PS> Set-SFTPDirectoryPath -Index 0 -Path /usr/bin
PS> Get-SFTPCurrentDirectory -Index 0
/usr/bin
We can get directory listings using the Get-SFTPDirectoryList command–the command will return a collection of objects referring to each of the files and directories in the given path.
PS> Get-SFTPDirectoryList -Index 0 -Path /tmp
FullName : /tmp/vmware-config2
LastAccessTime : 12/28/2013 8:54:40 AM
LastWriteTime : 12/28/2013 8:54:40 AM
Length : 4096
UserId : 0
FullName : /tmp/vmware-fonts0
LastAccessTime : 2/8/2013 7:50:24 PM
LastWriteTime : 2/8/2013 7:50:24 PM
Length : 4096
UserId : 0
FullName : /tmp/vmware-root
LastAccessTime : 6/28/2014 3:00:52 PM
LastWriteTime : 6/28/2014 3:00:52 PM
Length : 4096
UserId : 0
FullName : /tmp/vmware-config0
LastAccessTime : 2/8/2013 7:50:00 PM
LastWriteTime : 2/8/2013 7:50:00 PM
Length : 4096
UserId : 0
FullName : /tmp/poshssh
LastAccessTime : 6/28/2014 7:57:30 PM
LastWriteTime : 6/28/2014 7:58:38 PM
Length : 4096
UserId : 0
FullName : /tmp/vmware-fonts1
LastAccessTime : 4/26/2013 2:23:16 PM
LastWriteTime : 4/26/2013 2:23:16 PM
Length : 4096
UserId : 0
FullName : /tmp/vmware-tools-distrib
LastAccessTime : 12/28/2013 8:36:20 AM
LastWriteTime : 8/17/2013 1:51:12 PM
Length : 4096
UserId : 0
FullName : /tmp/vmware-fonts2
LastAccessTime : 12/28/2013 8:55:01 AM
LastWriteTime : 12/28/2013 8:55:01 AM
Length : 4096
UserId : 0
FullName : /tmp/.
LastAccessTime : 6/28/2014 9:42:56 PM
LastWriteTime : 6/28/2014 9:39:44 PM
Length : 4096
UserId : 0
FullName : /tmp/.ICE-unix
LastAccessTime : 6/28/2014 3:00:50 PM
LastWriteTime : 6/28/2014 3:00:50 PM
Length : 4096
UserId : 0
FullName : /tmp/vmware-config1
LastAccessTime : 4/26/2013 2:22:52 PM
LastWriteTime : 4/26/2013 2:22:52 PM
Length : 4096
UserId : 0
FullName : /tmp/..
LastAccessTime : 6/28/2014 3:00:51 PM
LastWriteTime : 6/28/2014 3:00:50 PM
Length : 4096
UserId : 0
PS> Get-SFTPDirectoryList -Index 0 -Path /tmp | gm
TypeName: Renci.SshNet.Sftp.SftpFile
Name MemberType Definition
---- ---------- ----------
Delete Method void Delete()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
MoveTo Method void MoveTo(string destFileName)
SetPermissions Method void SetPermissions(int16 mode)
ToString Method string ToString()
UpdateStatus Method void UpdateStatus()
Attributes Property Renci.SshNet.Sftp.SftpFileAttributes Attributes {get;set;}
Extensions Property System.Collections.Generic.IDictionary[string,string] Extensions {get;set;}
FullName Property string FullName {get;set;}
GroupCanExecute Property bool GroupCanExecute {get;set;}
GroupCanRead Property bool GroupCanRead {get;set;}
GroupCanWrite Property bool GroupCanWrite {get;set;}
GroupId Property int GroupId {get;set;}
IsBlockDevice Property bool IsBlockDevice {get;}
IsCharacterDevice Property bool IsCharacterDevice {get;}
IsDirectory Property bool IsDirectory {get;}
IsNamedPipe Property bool IsNamedPipe {get;}
IsRegularFile Property bool IsRegularFile {get;}
IsSocket Property bool IsSocket {get;}
IsSymbolicLink Property bool IsSymbolicLink {get;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
Length Property long Length {get;}
Name Property string Name {get;set;}
OthersCanExecute Property bool OthersCanExecute {get;set;}
OthersCanRead Property bool OthersCanRead {get;set;}
OthersCanWrite Property bool OthersCanWrite {get;set;}
OwnerCanExecute Property bool OwnerCanExecute {get;set;}
OwnerCanRead Property bool OwnerCanRead {get;set;}
OwnerCanWrite Property bool OwnerCanWrite {get;set;}
UserId Property int UserId {get;set;}
When working with files we can move, delete, upload, and download a specified files on a SFTP:
- Get-SFTPFile – Download a specified file from a remote SFTP session.
- Move-SFTPFile – Moves a specified file in a remote hosts through SFTP (Can be used to rename a file)
- Remove-SFTPFile – Deletes a specified file in a remote hosts through SFTP.
- Set-SFTPFile – Uploads a specified file to a given path using SFTP.
We can also create and delete directories on a target system:
- New-SFTPDirectory – Creates a directory in a remote hosts through SFTP.
- Remove-SFTPDirectory – Deletes a specified directory in a remote hosts through SFTP.
The Posh-SSH module should cover most of the basic needs. Each of the sessions include the session object that provides additional methods and properties. Most commands also return objects with additional methods and properties not shown by default that can be leveraged by an advanced user. I hope you find the module useful and if you come up with a new command or a bug fix do not hesitate to contribute.
Share on: