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.
#>
[CmdletBinding( DefaultParameterSetName = 'Auto' )]
param(
[Parameter( Mandatory )]
[string]
# The name of a saved PuTTY session.
$Session,
[AllowEmptyString()]
[Parameter( Mandatory )]
[string[]]
# One or more commands to execute in the remote session.
$Command,
[Parameter( ParameterSetName = 'IPv6', Mandatory )]
[switch]
# Forces use of IPv6. By default, Plink selects the IP version automatically, depending on your Windows networking configuration.
$IPv6,
[Parameter( ParameterSetName = 'IPv4', Mandatory )]
[switch]
# Forces use of IPv4. By default, Plink selects the IP version automatically, depending on your Windows networking configuration.
$IPv4,
[Parameter()]
[ValidateSet( 'Throw', 'Merge', 'Discard', 'Split' )]
[string]
# 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.
$StandardErrorBehavior = 'Throw'
);
[string] $Command = $Command -join "`n";
$exe = "${env:ProgramFiles}\PuTTY\plink.exe";
$params = @(
switch( $true ) {
$IPv6 { '-6'; }
$IPv4 { '-4'; }
default { ''; }
};
'-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 {
$OutputFile, $ErrorFile | Remove-Item -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'
rootThe -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.