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 C:\> 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 C:\> 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 C:\> 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 =theession is created, we can look at the session using the Get-SSHSession command

PS C:\> 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 C:\> 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 C:\> 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 C:\> Invoke-SSHCommand -Index 0 -Command "pwd" Host : 192.168.1.191 Output : /home/carlos ExitStatus : 0 PS C:\> Invoke-SSHCommand -Index 0 -Command "cd /" Host : 192.168.1.191 Output : ExitStatus : 0 PS C:\> 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 C:\> $session = Get-SSHSession -Index 1 PS C:\> $stream = $session.Session.CreateShellStream("dumb", 0, 0, 0, 0, 1000) PS C:\> $stream.Write("show ver<code>n") PS C:\> $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 C:\> $stream.Write("</code>n") PS C:\> $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 C:\> 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 C:\> 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 C:\> Get-SFTPCurrentDirectory -Index 0 /root PS C:\> Set-SFTPDirectoryPath -Index 0 -Path /usr/bin PS C:\> 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 C:\> 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 C:\> 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.

– 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)

– 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.

– 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.