Sample code for 30+ languages & platforms
PowerBuilder

SSH Parallel Remote Commands on Multiple Servers

See more SSH Examples

Demonstrates running the same command on several servers simultaneously. It is simply a matter of using one Ssh object per server, starting the command on each with QuickCmdSend, and then polling each connection with QuickCmdCheck until all have finished.

Background: This is the fan-out pattern behind configuration-management and monitoring tools: query or update a whole fleet in roughly the time the slowest single host takes, rather than the sum of all of them. Each server needs its own object because each has its own connection and authentication state. Note that results come back in whatever order the servers finish, which is why the example tracks completion per connection. Production code would keep the objects in arrays instead of repeating the logic per server.

Chilkat PowerBuilder Downloads

PowerBuilder
integer li_rc
integer li_Success
oleobject loo_Ssh1
oleobject loo_Ssh2
oleobject loo_Ssh3
integer li_Port
string ls_Password
string ls_Cmd
integer li_Channel1
integer li_Channel2
integer li_Channel3
integer li_PollTimeoutMs
integer li_NumFinished
integer li_Finished1
integer li_Finished2
integer li_Finished3
integer li_Ch1
string ls_Out1
integer li_Ch2
string ls_Out2
integer li_Ch3
string ls_Out3

li_Success = 0

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

//  Demonstrates running the same command on several servers simultaneously.  It is simply a
//  matter of using one Ssh object per server.

loo_Ssh1 = create oleobject
li_rc = loo_Ssh1.ConnectToNewObject("Chilkat.Ssh")
if li_rc < 0 then
    destroy loo_Ssh1
    MessageBox("Error","Connecting to COM object failed")
    return
end if
loo_Ssh2 = create oleobject
li_rc = loo_Ssh2.ConnectToNewObject("Chilkat.Ssh")

loo_Ssh3 = create oleobject
li_rc = loo_Ssh3.ConnectToNewObject("Chilkat.Ssh")

li_Port = 22

//  Normally you would not hard-code the password in source.  You should instead obtain it
//  from an interactive prompt, environment variable, or a secrets vault.
ls_Password = "mySshPassword"

li_Success = loo_Ssh1.Connect("ssh-server1.example.com",li_Port)
if li_Success = 0 then
    Write-Debug loo_Ssh1.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Success = loo_Ssh1.AuthenticatePw("mySshLogin",ls_Password)
if li_Success = 0 then
    Write-Debug loo_Ssh1.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Success = loo_Ssh2.Connect("ssh-server2.example.com",li_Port)
if li_Success = 0 then
    Write-Debug loo_Ssh2.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Success = loo_Ssh2.AuthenticatePw("mySshLogin",ls_Password)
if li_Success = 0 then
    Write-Debug loo_Ssh2.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Success = loo_Ssh3.Connect("ssh-server3.example.com",li_Port)
if li_Success = 0 then
    Write-Debug loo_Ssh3.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Success = loo_Ssh3.AuthenticatePw("mySshLogin",ls_Password)
if li_Success = 0 then
    Write-Debug loo_Ssh3.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

//  This command sleeps for 5 seconds and then prints the system date/time, making the parallel
//  execution easy to observe.
ls_Cmd = "sleep 5; date"

//  Start the command on each server.  QuickCmdSend returns immediately.
li_Channel1 = loo_Ssh1.QuickCmdSend(ls_Cmd)
if li_Channel1 < 0 then
    Write-Debug loo_Ssh1.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Channel2 = loo_Ssh2.QuickCmdSend(ls_Cmd)
if li_Channel2 < 0 then
    Write-Debug loo_Ssh2.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

li_Channel3 = loo_Ssh3.QuickCmdSend(ls_Cmd)
if li_Channel3 < 0 then
    Write-Debug loo_Ssh3.LastErrorText
    destroy loo_Ssh1
    destroy loo_Ssh2
    destroy loo_Ssh3
    return
end if

//  The command is now running on all three servers at once.  Poll each connection until every
//  command has finished.  (Production code would keep the objects in arrays rather than
//  repeating the logic.)
li_PollTimeoutMs = 50
li_NumFinished = 0
li_Finished1 = 0
li_Finished2 = 0
li_Finished3 = 0

do while li_NumFinished < 3
    if not li_Finished1 then
        li_Ch1 = loo_Ssh1.QuickCmdCheck(li_PollTimeoutMs)
        if li_Ch1 = -2 then
            Write-Debug loo_Ssh1.LastErrorText
            destroy loo_Ssh1
            destroy loo_Ssh2
            destroy loo_Ssh3
            return
        end if

        if li_Ch1 >= 0 then
            Write-Debug "---- ssh1 channel " + string(li_Ch1) + " finished ----"
            ls_Out1 = loo_Ssh1.GetReceivedText(li_Ch1,"utf-8")
            if loo_Ssh1.LastMethodSuccess = 0 then
                Write-Debug loo_Ssh1.LastErrorText
                destroy loo_Ssh1
                destroy loo_Ssh2
                destroy loo_Ssh3
                return
            end if

            Write-Debug ls_Out1
            li_Finished1 = 1
            li_NumFinished = li_NumFinished + 1
        end if

    end if

    if not li_Finished2 then
        li_Ch2 = loo_Ssh2.QuickCmdCheck(li_PollTimeoutMs)
        if li_Ch2 = -2 then
            Write-Debug loo_Ssh2.LastErrorText
            destroy loo_Ssh1
            destroy loo_Ssh2
            destroy loo_Ssh3
            return
        end if

        if li_Ch2 >= 0 then
            Write-Debug "---- ssh2 channel " + string(li_Ch2) + " finished ----"
            ls_Out2 = loo_Ssh2.GetReceivedText(li_Ch2,"utf-8")
            if loo_Ssh2.LastMethodSuccess = 0 then
                Write-Debug loo_Ssh2.LastErrorText
                destroy loo_Ssh1
                destroy loo_Ssh2
                destroy loo_Ssh3
                return
            end if

            Write-Debug ls_Out2
            li_Finished2 = 1
            li_NumFinished = li_NumFinished + 1
        end if

    end if

    if not li_Finished3 then
        li_Ch3 = loo_Ssh3.QuickCmdCheck(li_PollTimeoutMs)
        if li_Ch3 = -2 then
            Write-Debug loo_Ssh3.LastErrorText
            destroy loo_Ssh1
            destroy loo_Ssh2
            destroy loo_Ssh3
            return
        end if

        if li_Ch3 >= 0 then
            Write-Debug "---- ssh3 channel " + string(li_Ch3) + " finished ----"
            ls_Out3 = loo_Ssh3.GetReceivedText(li_Ch3,"utf-8")
            if loo_Ssh3.LastMethodSuccess = 0 then
                Write-Debug loo_Ssh3.LastErrorText
                destroy loo_Ssh1
                destroy loo_Ssh2
                destroy loo_Ssh3
                return
            end if

            Write-Debug ls_Out3
            li_Finished3 = 1
            li_NumFinished = li_NumFinished + 1
        end if

    end if

loop

loo_Ssh1.Disconnect()
loo_Ssh2.Disconnect()
loo_Ssh3.Disconnect()


destroy loo_Ssh1
destroy loo_Ssh2
destroy loo_Ssh3