Jump to content

SSH UDF


p4sCh
 Share

Recommended Posts

Hello everyone,

I've created a UDF for basic communication with SSH servers. I know there is already such a UDF, but I wasn't satisfied with it for my purpose, so I created a new one.

This UDF also acts as a wrapper for the plink executable. Its essential functions are _SSHConnect, _SSHSend, _SSHRecv and _SSHCloseSocket.

It does support multiple simultaneous connections and aims to be pretty robust. Feel free to share your opinions :)

Two of the included examples use a slightly modified version of Vintage Terminal by @Chimp

Spoiler
#include-once

#include <Constants.au3>
#include <Timers.au3>
#include <Array.au3>

OnAutoItExitRegister("__internal_closeAllSockets")

; #INDEX# =======================================================================================================================
; Title .........: SSH_UDF <ssh.au3>
; Udf Version....: 1.0.1 (10-2021)
; AutoIt Version : 3.3.14.5
; Language ......: English
; Description ...: Provides basic functionality to connect and communicate with SSH servers
; Author(s) .....: p4sCh
; Exe(s) ........: plink.exe; plink.exe is distributed under MIT License. See LICENSE.txt
; ===============================================================================================================================

; #PUBLIC FUNCTIONS# ============================================================================================================
; _SSHConnect       <Essential>
; _SSHLogin         <Optional>
; _SSHSend          <Essential>
; _SSHRecv          <Essential>
; _SSHCloseSocket   <Essential>
; _SSHSetConfig     <Optional>
; _SSHGetConfig     <Optional>
; _SSHSetPS1        <Misc>
; ===============================================================================================================================

; #INTERNAL FUNCTIONS# ==========================================================================================================
; __internal_SSHRecv
; __internal_applyInputEcho
; __internal_sanitizeOutput
; __internal_addSocket
; __internal_removeSocket
; __internal_isSocket
; __internal_getSocketIdx
; __internal_closeSocketAndReturn
; __internal_closeAllSockets
; hostToIP
; isValidIPv4
; isValidIPv6
; ===============================================================================================================================

; #CONSTANTS# ===================================================================================================================
Global Const $SSH_HOST_KEY_AUTO_ACCEPT = 0, $SSH_HOST_KEY_AUTO_ACCEPT_AND_STORE = 1, _
    $SSH_HOST_KEY_ABORT_IF_UNKNOWN = 2, $SSH_HOST_KEY_INTERACTIVE = 3
; ===============================================================================================================================

; #VARIABLES# ===================================================================================================================
Global $__plinkFolder = @ScriptDir & "\"
Global $__plinkExe = "plink.exe"
Global $__plinkFullPath = $__plinkFolder & $__plinkExe

Global $__echoLoginEnabled=True, $__stripBracketedPasteModeANSICodes=True, _
       $__stripPS1BeforeBell=True, $__stripANSIColorCodes=False, $__sanitizePlinkStderr=False

Dim $__socket[1], $__echoStr[1]
_ArrayPop($__socket)
_ArrayPop($__echoStr)
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHConnect
; Description ...: Establishes a connection with a ssh server
; Parameters ....: $host        - IPv4, IPv6 or hostname
;                  $login       - username
;                  $passwd      - password
;                  $port        - ssh port (default 22)
;                  $sshKeyFingerprint - how should _SSHConnect react when ssh key fingerprint of server is unknown? options are:
;                      $SSH_HOST_KEY_AUTO_ACCEPT          : accept ssh host key (do not store key in cache) (default)
;                      $SSH_HOST_KEY_AUTO_ACCEPT_AND_STORE: accept ssh host key and store in cache (registry) for future
;                      $SSH_HOST_KEY_ABORT_IF_UNKNOWN     : reject ssh host key if unknown (and disconnect)
;                      $SSH_HOST_KEY_INTERACTIVE          : don't answer when prompted, let user decide
; Return values .: Success      - Returns socket id greater than zero
;                               - Returns zero when connection was established and then canceled
;                                 (because ssh key fingerprint was unknown and $SSH_HOST_KEY_ABORT_IF_UNKNOWN was used)
;                  Failure      - Returns error code less than zero
; Author ........: p4sCh
; Modified.......:
; Remarks .......: Login(username) and password don't have to be passed to this function. You can also login when prompted.
;                  You can use _SSHLogin for logging in when prompted.
; Related .......: _SSHCloseSocket, _SSHLogin
; ===============================================================================================================================
Func _SSHConnect($host, $login="", $passwd="", $port=22, $sshKeyFingerprint=$SSH_HOST_KEY_AUTO_ACCEPT)
    $host = hostToIP($host)
    If $host == "" Then Return -1
    If Not FileExists($__plinkFullPath) Then
        ConsoleWriteError("SSH UDF: Path to plink executable is not valid! Path: "&$__plinkFullPath&@LF)
        Return -2
    EndIf

    Local $plinkCmd = $__plinkFullPath & " -P " & $port
    If $passwd <> "" Then $plinkCmd &= ' -pw "' & $passwd & '"'
    If Not StringIsSpace($login) Then
        $plinkCmd &= " " & $login & "@" & $host
    Else
        $plinkCmd &= " " & $host
    EndIf

    Local $socket = Run($plinkCmd, $__plinkFolder, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD + $STDERR_CHILD)
    If @error Then Return -3

    Local $sIdx = __internal_addSocket($socket)
    If $sshKeyFingerprint <> $SSH_HOST_KEY_INTERACTIVE Then
        Local $totalTimeout = _Timer_Init()
        Local $recvTimeout = -1
        Local $recv = ""
        Do
            $recv = __internal_SSHRecv($socket, False)
            If @error > 1 Then Return __internal_closeSocketAndReturn($socket, -4)
            If $recv <> "" Then
                $recvTimeout = _Timer_Init()
                If $__echoLoginEnabled Then $__echoStr[$sIdx] &= $recv
                If StringInStr($recv, "store key in cache?") Then
                    Local $success, $answer
                    If $sshKeyFingerprint = $SSH_HOST_KEY_AUTO_ACCEPT_AND_STORE Then
                        $answer = "y"&@CR
                    ElseIf $sshKeyFingerprint == $SSH_HOST_KEY_AUTO_ACCEPT Then
                        $answer = "n"&@CR
                    ElseIf $sshKeyFingerprint == $SSH_HOST_KEY_ABORT_IF_UNKNOWN Then
                        $answer = @CR
                    Else
                        Return __internal_closeSocketAndReturn($socket, -5)
                    EndIf
                    If $__echoLoginEnabled Then $__echoStr[$sIdx] &= $answer & @LF
                    $success = _SSHSend($socket, $answer)
                    If Not $success Then Return __internal_closeSocketAndReturn($socket, -6)
                    If $sshKeyFingerprint == $SSH_HOST_KEY_ABORT_IF_UNKNOWN Then Return __internal_closeSocketAndReturn($socket, 0)
                    ExitLoop
                EndIf
            Else
                Sleep(15)
            EndIf
        Until ($recvTimeout <> -1 And _Timer_Diff($recvTimeout) > 1000) Or _Timer_Diff($totalTimeout) > 5500
    EndIf

    Return $socket
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHLogin
; Description ...: If login or password was not passed to _SSHConnect, then _SSHLogin can be used
;                  to pass login information to interactive prompt
; Parameters ....: $host        - ssh socket
;                  $login       - username
;                  $passwd      - password
; Return values .: Success      - Returns True
;                  Failure      - Returns False
; Author ........: p4sCh
; Modified.......:
; Remarks .......: This function can be used when prompted login and/or password.
;                  This function might not work correctly in every case.
; Related .......: _SSHConnect
; ===============================================================================================================================
Func _SSHLogin($socket, $login="", $passwd="", $timeoutMs=5500)
    Local $sIdx = __internal_getSocketIdx($socket)
    If $sIdx < 0 Then Return False
    Local $loginEntered = False, $passwdEntered = False, $success = False
    Local $timer = _Timer_Init()
    Local $i = 0
    Do
        Local $recv
        If $i == 0 Then
            $recv = $__echoStr[$sIdx]
        Else
            $recv = __internal_SSHRecv($socket, False)
            If @error > 1 Then Return False
        EndIf
        If StringInStr($recv,"login as:") Then
            If $login == "" Or $loginEntered Then Return False
            If $__echoLoginEnabled Then
                If $i <> 0 Then $__echoStr[$sIdx] &= $recv
                $__echoStr[$sIdx] &= $login & @LF
            EndIf
            Local $ret = _SSHSend($socket, $login & @LF)
            If Not $ret Then Return False
            $loginEntered = True
        ElseIf StringInStr($recv,"password:") Then
            If $passwd == "" Or $passwdEntered Then Return False
            If $__echoLoginEnabled Then
                If $i <> 0 Then $__echoStr[$sIdx] &= $recv
                $__echoStr[$sIdx] &= "****" & @LF
            EndIf
            Local $ret = _SSHSend($socket, $passwd & @LF)
            If Not $ret Then Return False
            $passwdEntered = True
        Else
            If $i == 0 Then
                $i = 1
                ContinueLoop
            EndIf
            $__echoStr[$sIdx] &= $recv
            If $recv <> "" And ($loginEntered Or $passwdEntered) Then
                $success = True
                ExitLoop
            EndIf
        EndIf
        Sleep(10)
        $i += 1
    Until _Timer_Diff($timer) > $timeoutMs
    Return $success
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHSend
; Description ...: Send data to the ssh session.
; Parameters ....: $socket      - ssh socket
;                  $data        - string to send
; Return values .: Success      - Returns True
;                  Failure      - Returns False
; Author ........: p4sCh
; Modified.......:
; Remarks .......: When communicating with plink directly (e.g. ssh host key prompt) enter commands by appending @CR.
;                  When communicating with ssh server (everything else) often both @CR and @LF work for entering commands.
; Related .......: _SSHRecv
; ===============================================================================================================================
Func _SSHSend($socket, $data)
    If Not __internal_isSocket($socket) Then Return False
    StdinWrite($socket, $data)
    If @error Then Return False
    Return True
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHRecv
; Description ...: Receive data returned from plink (data source might be plink itself or ssh session)
; Parameters ....: $socket      - ssh socket
; Return values .: Success      - Returns data read from stdout
;                  Failure      - Sets @error greater than zero.
;                      @error=1:  Returns data read from stderr (can be important)
;                      @error=2:  Returns empty string. Socket invalid
;                      @error=3:  Returns empty string. Socket invalid OR stdout and stderr not available OR other error
;                                 Probably means you got disconnected from the ssh session
; Author ........: p4sCh
; Modified.......:
; Remarks .......:
; Related .......: _SSHSend
; ===============================================================================================================================
Func _SSHRecv($socket)
    Local $recv = __internal_SSHRecv($socket)
    SetError(@error)
    Return $recv
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHCloseSocket
; Description ...: Close a ssh socket returned by _SSHConnect
; Parameters ....: $socket      - ssh socket (ByRef)
; Return values .: N/A
; Author ........: p4sCh
; Modified.......:
; Remarks .......: This function sets passed ssh socket to zero
; Related .......: _SSHConnect
; ===============================================================================================================================
Func _SSHCloseSocket(ByRef $socket)
    If Not __internal_isSocket($socket) Then Return
    StdioClose($socket)
    ProcessClose($socket)
    __internal_removeSocket($socket)
    $socket = 0
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHSetConfig
; Description ...: Set ssh configuration values
; Parameters ....: $variableName    - name of the variable to be changed
;                  $value           - new value for that variable
; Return values .: Success          - Returns True. New value set
;                  Failure          - Returns False. Either non-existent variable name or wrong value type
; Author ........: p4sCh
; Modified.......:
; Remarks .......: Valid variableName:[value-type] pairs are:
;                  "plinkFolder":[String]         - Path where plink executable is located (default: @ScriptDir & "\")
;                  "plinkExe":[String]            - plink executable name (default: plink.exe)
;                  "echoLoginEnabled":[Bool]      - Receive full login procedure via _SSHRecv (default: True)
;                  "stripBracketedPasteModeANSICodes":[Bool] - Remove Bracketed-Paste-Mode ANSI Codes from ssh output
;                                                              These Codes are ESC[?2004h and ESC[?2004l (default: True)
;                  "stripPS1BeforeBell":[Bool]    - If found ESC[0; ANSI Code and then Bell-Character in one line of ssh output,
;                                                   these characters and everything in between get removed (default: True)
;                  "stripANSIColorCodes":[Bool]   - Removes ANSI Color Codes and ANSI SGR Codes from _SSHRecv (default: False)
;                  "sanitizePlinkStderr":[Bool]   - Applies sanitize functions (stripBracketedPasteModeANSICodes,
;                                                   stripPS1BeforeBell, stripANSIColorCodes) also to plinks stderr
;                                                   instead of only to its stdout (default: False)
; Related .......: _SSHGetConfig
; ===============================================================================================================================
Func _SSHSetConfig($variableName, $value)
    If $variableName == "" Or $value == "" Then Return False
    If StringLeft($variableName, 1) == "$" Then $variableName = StringRight($variableName, StringLen($variableName) - 1)

    Switch $variableName
        Case "plinkFolder", "plinkExe"
            If Not IsString($value) Then
                ConsoleWriteError("SSH Config error: Could not change $"&$variableName&". Wrong value type, String expected!"&@LF)
                Return False
            ElseIf $variableName == "plinkFolder" Then
                If StringRight($value, 1) <> "\" And StringRight($value, 1) <> "/" Then $value &= "\"
                $__plinkFullPath = $value & $__plinkExe
            ElseIf $variableName == "plinkExe" Then
                $__plinkFullPath = $__plinkFolder & $value
            EndIf
        Case "echoLoginEnabled", "stripBracketedPasteModeANSICodes", "stripPS1BeforeBell", "stripANSIColorCodes", _
             "sanitizePlinkStderr"
            If Not IsBool($value) Then
                ConsoleWriteError("SSH Config error: Could not change $"&$variableName&". Wrong value type, Bool expected!"&@LF)
                Return False
            EndIf
        Case "socket", "echoStr"
            Return False
    EndSwitch
    If Not Assign("__" & $variableName, $value, $ASSIGN_EXISTFAIL) Then
        ConsoleWriteError("SSH Config error: Variable $"&$variableName&" does not exist!"&@LF)
        Return False
    EndIf
    Return True
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHGetConfig
; Description ...: Get ssh configuration values
; Parameters ....: $variableName    - name of the variable to be returned
; Return values .: Success          - Returns value of the requested variable
;                  Failure          - Returns empty string and sets @error to non-zero
; Author ........: p4sCh
; Modified.......:
; Remarks .......: Names of returnable variables are: "plinkFolder", "plinkExe", "echoLoginEnabled",
;                  "stripBracketedPasteModeANSICodes", "stripPS1BeforeBell", "stripANSIColorCodes", "sanitizePlinkStderr"
;                  For explanation of these variables see _SSHSetConfig
; Related .......: _SSHSetConfig
; ===============================================================================================================================
Func _SSHGetConfig($variableName)
    If StringLeft($variableName, 1) == "$" Then $variableName = StringRight($variableName, StringLen($variableName) - 1)
    Local $value = Eval("__" & $variableName)
    Return SetError(@error, 0, $value)
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _SSHSetPS1
; Description ...: Changes the prompt string on the ssh server
; Parameters ....: $socket      - ssh socket
;                  $PS1         - new prompt string
; Return values .: Success      - Returns True
;                  Failure      - Returns False (might return True if 'export PS1="x"' command does not work on ssh server)
; Author ........: p4sCh
; Modified.......:
; Remarks .......: Works by executing the command 'export PS1="x"' where x is the string ($PS1) passed to the function
; Related .......: N/A
; ===============================================================================================================================
Func _SSHSetPS1($socket, $PS1 = "SSH: ")
    Return _SSHSend($socket, 'export PS1="' & $PS1 & '"' & @CR)
EndFunc

; #INTERNAL FUNCTIONS# ==========================================================================================================
; Author ........: p4sCh (except for isValidIPv4 and isValidIPv6)
; ..............->
Func __internal_SSHRecv($socket, $addEcho=True, $peek=False)
    Local $output = ""
    Local $sIdx = __internal_getSocketIdx($socket)
    If $sIdx < 0 Then Return SetError(2, 0, $output)
    Local $stdoutErr = False
    $output = StdoutRead($socket, $peek)
    If $output == "" Then
        If @error Then $stdoutErr = True
        If $addEcho Then __internal_applyInputEcho($output, $sIdx)
        $output &= StderrRead($socket, $peek)
        If $output <> "" Then
            If $__sanitizePlinkStderr Then __internal_sanitizeOutput($output)
            Return SetError(1, 0, $output)
        ElseIf @error And $stdoutErr == True Then
            Return SetError(3, 0, $output)
            EndIf
    Else
        __internal_sanitizeOutput($output)
        If $addEcho Then __internal_applyInputEcho($output, $sIdx)
    EndIf
    Return $output
EndFunc

Func __internal_applyInputEcho(ByRef $str, $idx)
    $str = $__echoStr[$idx] & $str
    $__echoStr[$idx] = ""
EndFunc

Func __internal_sanitizeOutput(ByRef $str)
    If $__stripBracketedPasteModeANSICodes Then
        $str = StringReplace($str,"�[?2004h","")
        $str = StringReplace($str,"�[?2004l"&@CR,"")
    EndIf
    If $__stripPS1BeforeBell Then
        If StringInStr($str, "�") Then
            Local $lines = StringSplit($str, @CRLF)
            Local $p1, $p2
            For $i=1 To $lines[0]
                $p1 = StringInStr($str,"�]0;")
                If $p1 <> 0 Then
                    $p2 = StringInStr($str, "�", 1, 1, $p1)
                    If $p2 <> 0 Then
                        $str = StringLeft($str, $p1-1) & StringRight($str, StringLen($str) - $p2)
                    EndIf
                EndIf
            Next
        EndIf
    EndIf
    If $__stripANSIColorCodes Then
        ; Matching Pattern: ESC\[[0-107][;0-107][;0-255]m               ; leading zeros are matched
        ; Matches ANSI Codes: SGR, 3-bit color, 4-bit color and 8-bit color
        $str = StringRegExpReplace($str,"�\[([0-1]0[0-7]|\d?\d)?(;[0-1]0[0-7]|;\d?\d)?(;[0-1]?\d?\d|;(0|2)[0-5][0-5])?m", "")
        ; Matching Pattern: ESC\[(38|48);2;[0-255];[0-255];[0-255]m     ; leading zeros are matched
        ; Matches ANSI Codes: True Color (24-bit)
        $str = StringRegExpReplace($str,"�\[(38|48);2;([0-1]?\d?\d|(0|2)[0-5][0-5]);([0-1]?\d?\d|(0|2)[0-5][0-5]);([0-1]?\d?\d|(0|2)[0-5][0-5])m","")
    EndIf
EndFunc

Func __internal_addSocket($socket, $echoStr = "")
    ReDim $__socket[UBound($__socket) + 1]
    ReDim $__echoStr[UBound($__echoStr) + 1]
    $__socket[UBound($__socket) - 1] = $socket
    $__echoStr[UBound($__echoStr) - 1] = $echoStr
    Return UBound($__socket) - 1
EndFunc

Func __internal_removeSocket($socket)
    Local $idx = _ArraySearch($__socket, $socket)
    If $idx >= 0 Then
        If _ArrayDelete($__socket, $idx) >= 0 Then
            _ArrayDelete($__echoStr, $idx)
            Return True
        EndIf
    EndIf
    Return False
EndFunc

Func __internal_isSocket($socket)
    If _ArraySearch($__socket, $socket) >= 0 Then Return True
    Return False
EndFunc

Func __internal_getSocketIdx($socket)
    Return _ArraySearch($__socket, $socket)
EndFunc

Func __internal_closeSocketAndReturn($socket, $retValue)
    _SSHCloseSocket($socket)
    Return $retValue
EndFunc

Func __internal_closeAllSockets()
    Local $i
    For $i=0 To UBound($__socket) -1
        StdioClose($__socket[$i])
        ProcessClose($__socket[$i])
    Next
    ReDim $__socket[1]
    ReDim $__echoStr[1]
    _ArrayPop($__socket)
    _ArrayPop($__echoStr)
EndFunc

Func hostToIP($host)
    If StringIsSpace($host) Then
        Return ""
    ElseIf isValidIPv4($host) Or isValidIPv6($host) Then
        Return $host
    Else
        TCPStartup()
        Local $IP = TCPNameToIP($host)
        If @error Then ConsoleWriteError("SSH UDF: Could not resolve IP/Domain: " & $host & @LF)
        TCPShutdown()
        Return $IP
    EndIf
EndFunc

; Source: jchd https://www.autoitscript.com/forum/topic/163160-regular-expression-to-confirm-an-ipv4-address/?do=findComment&comment=1188014
Func isValidIPv4($ipv4)
    Return StringRegExp($ipv4, "^(?:[1-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(?:\.(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}$", 0)
EndFunc

; Source: James https://www.autoitscript.com/forum/topic/144168-validate-ipv6-address/
Func isValidIPv6($ipv6)
    Return StringRegExp($ipv6, "^(([\da-f]{0,4}:{0,2}){1,8})$", 0)
EndFunc
; ===============================================================================================================================

 

Download

The download includes ssh.au3 (UDF), plink.exe (necessary), vintage terminal and code examples:

Spoiler

SSH UDF.zip (version 1.0)

Version 1.0.1

- fixed rare _SSHConnect bug where "ssh-host-key prompt" was not answered

SSH UDF 1.0.1.zip

 

Edited by p4sCh
added version 1.0.1
Link to comment
Share on other sites

On 9/30/2021 at 3:07 PM, gcriaco said:

It works fine. Many thanks and compliments!

Thank you 😊

On 10/2/2021 at 9:45 AM, Chimp said:

Hi @p4sCh, good job!

thanks for sharing :)

Thanks for providing the vintage terminal. It really took the examples to another level!

You might want to consider to update the original vintage terminal thread with the modified version from this UDF.

It does have some bug fixes, new features and should have noticeable better performance.

On 10/1/2021 at 5:11 AM, JiBe said:

this UDF SSH - AutoIt Example Scripts - AutoIt Forums (autoitscript.com) support multiple simultaneous connections.

 

I know :). And it supports many plink settings which can not be adjusted in this UDF. I had different reasons to make another SSH UDF.

Link to comment
Share on other sites

Hi,

Thanks for sharing but ...

I wonder why you use an external app to create an SSH cleient.

While W10 has this out of the box using the SSH command

usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
           [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
           [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
           [-i identity_file] [-J [user@]host[:port]] [-L address]
           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
           [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] destination [command]

Which also integrates in Windows Terminal 

https://docs.microsoft.com/en-us/windows/terminal/tutorials/ssh

 

Link to comment
Share on other sites

13 hours ago, ptrex said:

Hi,

Thanks for sharing but ...

I wonder why you use an external app to create an SSH cleient.

While W10 has this out of the box using the SSH command

Just because I didn't knew about this feature 😅
Very interesting, thank you. At the moment I have little time but I consider changing the UDF to use this method primarily or as alternative to plink. Would be nice to drop the additional executable.

Edit: Looks like this command is only available from Win10 (Version 1709+). So on an older OS you would have to use plink instead.

Edited by p4sCh
Link to comment
Share on other sites

  • 1 year later...

I tried the original SSH UDF and the upgraded v2.1 but I keep getting:
No supported authentication methods available (server sent: publickey)

 

I know I'm using the correct IP/Port User/Pass.

I am using it on Windows 11.  Do I need to have my PPK file anywhere for this to work or something?

 

Edit: Ok... I figured out my issue.  I had to launch pageant to load my ppk file.  Now it is working. 

Edit2: I was also able to add "-i [pathtoPPKfile]" to the $plinkCmd

Which then works without pageant.

Edited by Proph
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...