Sample code for 30+ languages & platforms
PureBasic

SSH Remote Shell

See more SSH Examples

Demonstrates how to start a shell on a remote SSH server, run a command, and retrieve the output.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkSsh.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This example assumes the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    ssh.i = CkSsh::ckCreate()
    If ssh.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ; Hostname may be an IP address or hostname:
    hostname.s = "www.some-ssh-server.com"
    port.i = 22

    ; Connect to an SSH server:
    success = CkSsh::ckConnect(ssh,hostname,port)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Wait a max of 5 seconds when reading responses..
    CkSsh::setCkIdleTimeoutMs(ssh, 5000)

    ; Authenticate using login/password:
    success = CkSsh::ckAuthenticatePw(ssh,"myLogin","myPassword")
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Open a session channel.  (It is possible to have multiple
    ; session channels open simultaneously.)
    channelNum.i
    channelNum = CkSsh::ckOpenSessionChannel(ssh)
    If channelNum < 0
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Some SSH servers require a pseudo-terminal
    ; If so, include the call to SendReqPty.  If not, then 
    ; comment out the call to SendReqPty.
    ; Note: The 2nd argument of SendReqPty is the terminal type,
    ; which should be something like "xterm", "vt100", "dumb", etc.
    ; A "dumb" terminal is one that cannot process escape sequences.
    ; Smart terminals, such as "xterm", "vt100", etc. process
    ; escape sequences.  If you select a type of smart terminal,
    ; your application will receive these escape sequences
    ; included in the command's output.  Use "dumb" if you do not
    ; want to receive escape sequences.  (Assuming your SSH
    ; server recognizes "dumb" as a standard dumb terminal.)
    termType.s = "dumb"
    widthInChars.i = 120
    heightInChars.i = 40
    ; Use 0 for pixWidth and pixHeight when the dimensions
    ; are set in number-of-chars.
    pixWidth.i = 0
    pixHeight.i = 0
    success = CkSsh::ckSendReqPty(ssh,channelNum,termType,widthInChars,heightInChars,pixWidth,pixHeight)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Start a shell on the channel:
    success = CkSsh::ckSendReqShell(ssh,channelNum)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Start a command in the remote shell.  This example
    ; will send a "ls" command to retrieve the directory listing.
    success = CkSsh::ckChannelSendString(ssh,channelNum,"ls" + Chr(13) + Chr(10),"ansi")
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Send an EOF.  This tells the server that no more data will 
    ; be sent on this channel.  The channel remains open, and
    ; the SSH client may still receive output on this channel.
    success = CkSsh::ckChannelSendEof(ssh,channelNum)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Read whatever output may already be available on the
    ; SSH connection.  ChannelReadAndPoll returns the number of bytes
    ; that are available in the channel's internal buffer that
    ; are ready to be "picked up" by calling GetReceivedText
    ; or GetReceivedData.
    ; A return value of -1 indicates failure.
    ; A return value of -2 indicates a failure via timeout.

    ; The ChannelReadAndPoll method waits
    ; for data to arrive on the connection usingi the IdleTimeoutMs
    ; property setting.  Once the first data arrives, it continues
    ; reading but instead uses the pollTimeoutMs passed in the 2nd argument:
    ; A return value of -2 indicates a timeout where no data is received.
    n.i
    pollTimeoutMs.i = 2000
    n = CkSsh::ckChannelReadAndPoll(ssh,channelNum,pollTimeoutMs)
    If n < 0
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Close the channel:
    success = CkSsh::ckChannelSendClose(ssh,channelNum)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Perhaps we did not receive all of the commands output.
    ; To make sure,  call ChannelReceiveToClose to accumulate any remaining
    ; output until the server's corresponding "channel close" is received.
    success = CkSsh::ckChannelReceiveToClose(ssh,channelNum)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Let's pickup the accumulated output of the command:
    cmdOutput.s = CkSsh::ckGetReceivedText(ssh,channelNum,"ansi")
    If CkSsh::ckLastMethodSuccess(ssh) <> 1
        Debug CkSsh::ckLastErrorText(ssh)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ; Display the remote shell's command output:
    Debug cmdOutput

    ; Disconnect
    CkSsh::ckDisconnect(ssh)


    CkSsh::ckDispose(ssh)


    ProcedureReturn
EndProcedure