---
id: file--telnet-ssh
title: "Remote shell"
summary: "Runs a script on a remote system over SSH or Telnet for every incoming record (bash or another POSIX shell, or PowerShell on Windows and Linux servers over SSH) and returns the output as a `TextRecord`. Values from the input record can be injected into the script with placeholders."
audience: user
keywords: "input, output, remotehost, portoption, customport, protocol, shell, authtype, username, password, privatekey, privatekeypassphrase, timeoutsec, failonerror, script"
---
# Remote shell

Runs a script on a remote system over SSH or Telnet for every incoming record (bash or another POSIX shell, or PowerShell on Windows and Linux servers over SSH) and returns the output as a `TextRecord`. Values from the input record can be injected into the script with placeholders.

## Pins

| Pin | Kind | Types | Description |
|---|---|---|---|
| Input | input | any | Triggers one script run. Its properties fill the script placeholders. |
| Output | output | `Viaducta.Plugins.TextPlugin.Types.TextRecord` | Script output in `Value` (`Name` and `ContentType` are empty). |

## Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `RemoteHost` | string | | Required. Host name or IP of the remote system. |
| `PortOption` | dropdown: `0` Default, `1` Custom | `0` | `0`: port 23 (Telnet) or 22 (SSH). `1`: use `CustomPort`. |
| `CustomPort` | integer (optional) | | Shown when `PortOption` is `1`; must then be 1-65535 or the flow fails to start. |
| `Protocol` | dropdown: `0` Telnet, `1` SSH | `0` | Connection protocol. |
| `Shell` | dropdown: `0` Login shell, `1` Windows PowerShell, `2` PowerShell 7 | `0` | Shown for SSH. `0`: the user's login shell runs the script (bash on Linux). `1`: `powershell.exe` (Windows PowerShell 5.1). `2`: `pwsh` (PowerShell 7, Windows or Linux). Telnet always uses the login shell. |
| `AuthType` | dropdown: `0` Password, `1` Private key | `0` | Shown for SSH. Telnet always uses the password. |
| `Username` | string (max 256) | | Login user. |
| `Password` | password (max 256) | | Login password. Hidden for SSH with `AuthType` `1`. |
| `PrivateKey` | password | | Shown when `AuthType` is `1`: path of a key file on the server, or the key text (starts with `-----BEGIN`). Required then. |
| `PrivateKeyPassphrase` | password | | Shown when `AuthType` is `1`: passphrase of an encrypted key. |
| `TimeOutSec` | number | `10` | SSH: limit for connecting and logging in. Telnet: limit for connecting, for each login step and for the whole script. |
| `FailOnError` | checkbox | `true` | Raise a recoverable error when the exit code of the script is not 0. |
| `Script` | script (BashEditor) | | Commands to run: bash, or PowerShell when `Shell` is `1` or `2`. Lines starting with `#` are comments. Placeholders `{Name\|Type\|default}`. |

## Script and placeholders

```bash
# list a folder given by the input record
cd {FolderName|String|/tmp}
ls -al
```

- `{Name|Type}` or `{Name|Type|default}` (on one line) is replaced by the value of property `Name` of the input record (text form). If the value is null the default is used, or an empty string without default. `Type` is informational only.
- Other curly brackets are shell syntax and left alone: `${HOME}`, `{a,b}`, `find -exec {} \;`, `awk '{print $1}'`.
- At flow start the plugin checks that the input type has every placeholder property; otherwise the flow fails to start.
- Values are inserted as-is (no quoting or escaping). Quote them in the script and do not pass untrusted input.
- Windows line endings are converted to `\n` before sending.
- PowerShell: a script block with a short pipeline, such as `{ gci | sort }`, looks like a placeholder. Write the full command name (`{ gci | Sort-Object }`) or start it with `$_`.

## PowerShell

```powershell
# disk space of a Windows server, drive given by the input record
$ErrorActionPreference = 'Stop'
Get-PSDrive -Name '{Drive|String|C}' | Select-Object Name, Used, Free | Format-Table -AutoSize | Out-String -Width 200
```

- Set `Protocol` to `1` (SSH) and `Shell` to `1` or `2`. A Windows server needs the OpenSSH Server (a Windows feature since Windows 10 1809 and Windows Server 2019). WinRM and Telnet are not supported.
- The plugin runs `powershell.exe` (or `pwsh`) `-NoProfile -NonInteractive -EncodedCommand` with the script. The script travels base64-encoded, so its quotes and special characters reach PowerShell unchanged, whatever the server's default SSH shell is (cmd.exe, PowerShell or bash).
- In front of the script the plugin adds one line that switches off progress output and makes the output UTF-8. Line numbers in PowerShell error messages are therefore one higher than in the editor.
- The encoded command must stay under 8000 characters (cmd.exe's limit on Windows): about 2,900 characters of script after the placeholders are filled. A longer script fails with a recoverable error. Keep long scripts in a `.ps1` file on the server and call it from the script (the server's execution policy then applies).
- Exit code: 0 when the last command succeeded, 1 when it failed; `exit 3` sets it. A failing program (exe) as the last command also gives 1; end the script with `exit $LASTEXITCODE` to pass its own code. `$ErrorActionPreference = 'Stop'` stops at the first error (like `set -e`).
- `Value` is the text PowerShell prints. Objects are formatted as on the console; use `Format-Table`, `Out-String -Width`, `ConvertTo-Json` or `ConvertTo-Csv` to control it. Errors go to standard error and are in the error message when the script fails; error records that PowerShell writes as CLIXML are turned into plain text.

## Behaviour

- Every record opens a new connection, runs the script, closes the connection and calls `Output` once.
- **SSH:** the whole script is executed as one remote command (the user's login shell runs all lines, or PowerShell: see above). `Value` contains the standard output. The host key is accepted without verification.
- **Telnet login:** with a user name, the plugin waits up to `TimeOutSec` for a `login:` / `user:` / `username:` prompt (or a `password:` prompt, for servers that ask the password only) and then for the password prompt. After the credentials it waits for the answer: a failure message (`Login incorrect`, `Permission denied`, ...) or a new login prompt is an unrecoverable login error; a text ending like a shell prompt (`$`, `#`, `>`, `%`) means logged in. A missing prompt is a recoverable timeout error. With neither user nor password no login is done.
- **Telnet script:** the plugin switches off the prompt and echo, and sends the script between two marker lines; the last marker carries the exit code. `Value` is the output between the markers. Telnet negotiation and terminal escape codes are removed; text is sent and read as UTF-8. If the remote host closes the connection, the run ends at once with an error. The remote side must run a POSIX shell (sh, bash, ash, ...); devices with their own command line (for example routers) never send the end marker and the script fails with a timeout.
- **Exit code:** the exit code is the one of the last command (as in any shell script). With `FailOnError` a non-zero exit code is a recoverable error whose message has the exit code and standard error (SSH) or the output (Telnet), and nothing is sent to `Output`. Without `FailOnError` the output is sent whatever the exit code. Over SSH, start the script with `set -e` (PowerShell: `$ErrorActionPreference = 'Stop'`) to stop at the first failing command.
- **Errors:** wrong credentials or a bad private key are unrecoverable errors. Other connection failures (host down, refused, timeout) and script failures are recoverable. The messages include the reason.
- When the flow is stopped during a run, no output is sent.
- With data tracing on, the communication log is written to the debug log. The Telnet password is masked there.

## Notes

- Telnet connects to IPv4 or IPv6 addresses (IPv4 first when the host has both).
- The SSH script has no time limit; a hanging command blocks the flow.
- Use expression settings (`=Secrets.ServerPassword`, `=Secrets.ServerKey`) for the password and the private key.

## Example

```json
{ "RemoteHost": "10.0.0.15", "Protocol": 1, "PortOption": 0, "Username": "ops", "Password": "=Secrets.OpsPassword",
  "Script": "df -h {Mount|String|/}" }
```

Timer → Script (sets `Mount`) → **Remote shell** → Text parser → Alarm

A Windows service status as JSON:

```json
{ "RemoteHost": "winsrv01", "Protocol": 1, "Shell": 1, "Username": "svc-viaducta", "Password": "=Secrets.WinPassword",
  "Script": "Get-Service -Name '{Service|String|Spooler}' | Select-Object Name, Status | ConvertTo-Json" }
```
