Plink is part of the PuTTY suite. Plink is primarily used to run automated operations (rather than interactive sessions) on a remote server, using the SSH protocol.
To reliably run Plink from PowerShell, you need to redirect Plink's input from $null
. This avoids the problem that both PowerShell and Plink might attempt to read from the console, resulting in an exception: Cannot read keys when either application does not have a console or when console input has been redirected.
The function Invoke-Plink
encapsulates the call of Plink:
function Invoke-Plink {
<#
.SYNOPSIS
Executes a remote command via Plink.
.PARAMETER Session
The name of a saved PuTTY session.
.PARAMETER Command
One or more commands to execute in the remote session.
.PARAMETER IPv6
Forces use of IPv6. By default, Plink selects the IP version automatically, depending on your Windows networking configuration.
.PARAMETER IPv4
Forces use of IPv4. By default, Plink selects the IP version automatically, depending on your Windows networking configuration.
.PARAMETER StandardErrorBehavior
Specifies how to handle output written to stderr by the remote command:
• 'Throw' will raise an exception if any output was written to stderr.
• 'Merge' will combine stdout and stderr output, similar to a console.
• 'Discard' will simply omit any stderr output.
• 'Split' will return stdout and stderr output in two distinct properties.
#>
[CmdletBinding( DefaultParameterSetName = 'Auto' )]
param(
[Parameter( Mandatory )]
[string]
$Session,
[AllowEmptyString()]
[Parameter( Mandatory )]
[string[]]
$Command,
[Parameter( ParameterSetName = 'IPv6', Mandatory )]
[switch]
$IPv6,
[Parameter( ParameterSetName = 'IPv4', Mandatory )]
[switch]
$IPv4,
[Parameter()]
[ValidateSet( 'Throw', 'Merge', 'Discard', 'Split' )]
[string]
$StandardErrorBehavior = 'Throw'
);
[string] $Command = $Command | Join-String -Separator "`n";
$exe = "$env:ProgramFiles\PuTTY\plink.exe";
$params = @(
$IPv6 ? '-6' : $IPv4 ? '-4' : '';
'-batch';
'-load'
$Session;
$Command;
);
$OutputFile = [System.IO.Path]::GetTempFileName();
$ErrorFile = [System.IO.Path]::GetTempFileName();
try {
switch( $StandardErrorBehavior ) {
'Throw' {
$null | & $exe $params 1>$OutputFile 2>$ErrorFile;
$ErrorContent = Get-Content -LiteralPath $ErrorFile;
if( $ErrorContent ) {
throw $ErrorContent;
} else {
Get-Content -LiteralPath $OutputFile;
}
}
'Merge' {
$null | & $exe $params 1>$OutputFile 2>&1;
Get-Content -LiteralPath $OutputFile;
}
'Discard' {
$null | & $exe $params 1>$OutputFile 2>$null;
Get-Content -LiteralPath $OutputFile;
}
'Split' {
$null | & $exe $params 1>$OutputFile 2>$ErrorFile;
[pscustomobject] @{
Output = Get-Content -LiteralPath $OutputFile;
Errors = Get-Content -LiteralPath $ErrorFile;
};
}
}
} finally {
Remove-Item -LiteralPath $OutputFile -ErrorAction 'SilentlyContinue';
Remove-Item -LiteralPath $ErrorFile -ErrorAction 'SilentlyContinue';
}
}
Invoke-Plink.ps1Use the main PuTTY program to configure and save a session, then call this function as follows:
PS C:\> Invoke-Plink -Session 'example.net' -Command 'whoami'
root
The -StandardErrorBehavior
parameter specifies how to handle output written to stderr by the remote command:
-StandardErrorBehavior Merge
will combine stdout and stderr output, similar to a console:
PS C:\> Invoke-Plink -Session 'example.net' -Command 'whoami; cp;' -StandardErrorBehavior Merge
root
cp: missing file operand
Try 'cp --help' for more information.
-StandardErrorBehavior Split
will return stdout and stderr output in two distinct properties of a pscustomobject
:
PS C:\> Invoke-Plink -Session 'example.net' -Command 'whoami; cp;' -StandardErrorBehavior Split
Output Errors
------ ------
root {cp: missing file operand, Try 'cp --help' for more information.}
-StandardErrorBehavior Discard
will simply omit any stderr output:
PS C:\> Invoke-Plink -Session 'example.net' -Command 'whoami; cp;' -StandardErrorBehavior Discard
root
-StandardErrorBehavior Throw
will raise an exception if any output was written to stderr:
PS C:\> Invoke-Plink -Session 'example.net' -Command 'whoami; cp;' -StandardErrorBehavior Throw
Exception: C:\Users\Christoph\Documents\PowerShell\Invoke-Plink.ps1:71
Line |
71 | throw $ErrorContent;
| ~~~~~~~~~~~~~~~~~~~
| cp: missing file operand Try 'cp --help' for more information.