# encoding: ascii
# api: powershell
# title: SharpSsh 3
# description: I’ve tweaked New-SshSession again, this time it supports multiple parameter sets (including one with the password in plain text, and one which takes a PSCredential).
# version: 0.1
# type: script
# author: Joel Bennett
# license: CC0
# function: ConvertTo-SecureString
# x-poshcode-id: 2099
# x-derived-from-id: 3601
# x-archived: 2017-03-12T05:29:49
# x-published: 2011-08-24T21:41:00
#
# A few wrapper functions to make working with the SSH portion of SharpSSH easier: New-SshSession, Invoke or Send Ssh commands, Receive output, all with support for “Expect” ... which means we’ll continue reading from the ssh output until we see the expected output, and then stop.
#
#requires -version 2.0
## A simple SSH Scripting module for PowerShell
## History:
## v1 - Initial Script
## v2 - Capture default prompt in New-SshSession
## v3 - Update to advanced functions, require 2.0, and add basic help
## USING the binaries from:
## http://downloads.sourceforge.net/sharpssh/SharpSSH-1.1.1.13.bin.zip
[void][reflection.assembly]::LoadFrom( (Resolve-Path "~\Documents\WindowsPowerShell\Libraries\Tamir.SharpSSH.dll") )
Function ConvertTo-SecureString {
#.Synopsis
# Helper function which converts a string to a SecureString
Param([string]$input)
$result = new-object System.Security.SecureString
foreach($c in $input.ToCharArray()) {
$result.AppendChar($c)
}
$result.MakeReadOnly()
return $result
}
Function ConvertTo-PSCredential {
#.Synopsis
# Helper function which converts a NetworkCredential to a PSCredential
Param([System.Net.NetworkCredential]$Credential)
$result = new-object System.Security.SecureString
foreach($c in $input.ToCharArray()) {
$result.AppendChar($c)
}
$result.MakeReadOnly()
New-Object System.Management.Automation.PSCredential "$($Credential.UserName)@$($Credential.Domain)", (ConvertTo-SecureString $Credential.Password)
}
## NOTE: These are still bare minimum functions, and only cover ssh, not sftp or scp (see here: http://poshcode.org/1034)
## IMPORTANT: if you "expect" something that does NOT get output, you'll be completely stuck and unable to 'break'
##
## As a suggestion, the best way to handle the output is to "expect" your prompt, and then do
## select-string matching on the output that was captured before the prompt.
function New-SshSession {
<#
.Synopsis
Create an SSH session to a remote server
.Description
Connect to a specific SSH server with the specified credentials. Supports RSA KeyFile connections.
.Parameter HostName
The server to SSH into
.Parameter UserName
The user name to use for login
.Parameter Password
The Password for login (Note: you really should pass this as a System.Security.SecureString, but it will accept a string instead)
.Parameter KeyFile
An RSA keyfile for ssh secret key authentication (INSTEAD of username/password authentication).
.Parameter Credentials
A PSCredential object containing all the information needed to log in. The login name should be in the form user@host
.Parameter Passthru
If passthru is specified, the new SshShell is returned.
.Example
New-SshSession Microsoft.com BillG Micr050ft
Description
-----------
Creates a new ssh session with the ssh server at Microsoft.com using the 'BillG' as the login name and 'Micr050ft' as the password (please don't bother trying that).
.Example
New-SshSession Microsoft.com -Keyfile BillGates.ppk
Description
-----------
Creates a new ssh session with the ssh server at Microsoft.com using the credentials supplied in the BillGates.ppk private key file.
.Example
$MSCred = Get-Credential BillG@Microsoft.com # prompts for password
New-SshSession $MSCred
Description
-----------
Creates a new ssh session based on the supplied credentials. Uses the output of $MsCred.GetNetworkCredential() for the server to log into (domain) and the username and password.
#>
[CmdletBinding(DefaultParameterSetName='NamePass')]
Param(
[Parameter(Position=0,Mandatory=$true,ParameterSetName="NamePass",ValueFromPipelineByPropertyName=$true)]
[Parameter(Position=0,Mandatory=$true,ParameterSetName="RSAKeyFile",ValueFromPipelineByPropertyName=$true)]
[string]$HostName
,
[Parameter(Position=1,Mandatory=$false,ParameterSetName="NamePass",ValueFromPipelineByPropertyName=$true)]
[string]$UserName
,
[Parameter(Position=2,Mandatory=$false,ParameterSetName="NamePass",ValueFromPipelineByPropertyName=$true)]
$Password
,
[Parameter(Position=1,Mandatory=$true,ParameterSetName="RSAKeyFile",ValueFromPipelineByPropertyName=$true)]
[string]$KeyFile
,
[Parameter(Position=0,Mandatory=$true,ParameterSetName="PSCredential",ValueFromPipeline=$true)]
[System.Management.Automation.PSCredential]$Credentials
,
[switch]$Passthru
)
process {
switch($PSCmdlet.ParameterSetName) {
'RSAKeyFile' {
$global:LastSshSession = new-object Tamir.SharpSsh.SshShell $HostName, $UserName
$global:LastSshSession.AddIdentityFile( (Convert-Path (Resolve-Path $KeyFile)) )
}
'NamePass' {
if(!$UserName -or !$Password) {
$Credentials = $Host.UI.PromptForCredential("SSH Login Credentials",
"Please specify credentials in user@host format",
"$UserName@$HostName","")
} else {
if($Password -isnot [System.Security.SecureString]) {
$Password = ConvertTo-SecureString $Password
}
$Credentials = New-Object System.Management.Automation.PSCredential "$UserName@$HostName", $Password
}
}
}
if($Credentials) {
$global:LastSshSession = new-object Tamir.SharpSsh.SshShell `
$Credentials.GetNetworkCredential().Domain,
$Credentials.GetNetworkCredential().UserName,
$Credentials.GetNetworkCredential().Password
}
$global:LastSshSession.Connect()
$global:LastSshSession.RemoveTerminalEmulationCharacters = $true
if($Passthru) { return $global:LastSshSession }
$global:LastSshSession.WriteLine("")
sleep -milli 500
$global:defaultSshPrompt = [regex]::Escape( $global:LastSshSession.Expect().Split("`n")[-1] )
}
}
function Remove-SshSession {
<#
.Synopsis
Exits the open SshSession
#>
Param([Tamir.SharpSsh.SshShell]$SshShell=$global:LastSshSession)
$SshShell.WriteLine( "exit" )
sleep -milli 500
if($SshShell.ShellOpened) { Write-Warning "Shell didn't exit cleanly, closing anyway." }
$SshShell.Close()
$SshShell = $null
}
function Invoke-Ssh {
<#
.Synopsis
Executes an SSH command and Receives output
.Description
Invoke-Ssh is basically the same as a Send-Ssh followed by a Receive-Ssh, except that Expect defaults to $defaultSshPrompt (which is read in New-SshSession)
.Parameter Command
The command to send
.Parameter Expect
A regular expression for expect. The ssh session will wait for a line that matches this regular expression to be output before returning, and will return all the text up to AND INCLUDING the line that matches.
Defaults
.Parameter SshShell
The shell to invoke against. Defaults to the LastSshSession
#>
Param(
[string]$Command
, [regex]$Expect = $global:defaultSshPrompt ## there ought to be a non-regex parameter set...
, [Tamir.SharpSsh.SshShell]$SshShell=$global:LastSshSession
)
if($SshShell.ShellOpened) {
$SshShell.WriteLine( $command )
if($expect) {
$SshShell.Expect( $expect ).Split("`n")
}
else {
sleep -milli 500
$SshShell.Expect().Split("`n")
}
}
else { throw "The ssh shell isn't open!" }
}
function Send-Ssh {
<#
.Synopsis
Executes an SSH command without receiving input
.Description
Sends a command to an ssh session
.Parameter Command
The command to send
.Parameter SshShell
The shell to send to. Defaults to the LastSshSession
#>
Param(
[string]$command
, [Tamir.SharpSsh.SshShell]$SshShell=$global:LastSshSession
)
if($SshShell.ShellOpened) {
$SshShell.WriteLine( $command )
}
else { throw "The ssh shell isn't open!" }
}
function Receive-Ssh {
<#
.Synopsis
Receives output from an SSH session
.Description
Retrieves output from an SSH session until the text matches the Expect pattern
.Parameter Expect
A regular expression for expect. The ssh session will wait for a line that matches this regular expression to be output before returning, and will return all the text up to AND INCLUDING the line that matches.
.Parameter SshShell
The shell to wait for. Defaults to the LastSshSession
#>
Param(
[RegEx]$expect ## there ought to be a non-regex parameter set...
, [Tamir.SharpSsh.SshShell]$SshShell=$global:LastSshSession
)
if($SshShell.ShellOpened) {
if($expect) {
$SshShell.Expect( $expect ).Split("`n")
}
else {
sleep -milli 500
$SshShell.Expect().Split("`n")
}
}
else { throw "The ssh shell isn't open!" }
}