Last active
April 17, 2023 14:16
-
-
Save Hashbrown777/5acd3acfc532eea8c30b752c3885b1d3 to your computer and use it in GitHub Desktop.
A workaround for Windows official openssh client not supporting -f nor -N
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#accepts all arguments for ssh except command, -N and -f | |
#command can be piped in | |
Filter ssh-f { | |
$N = $False | |
if (!$_) { | |
#the same as -N | |
$_ = 'read' | |
$N = $True | |
} | |
$_ = 'echo SUCCESS;' + $_ | |
$args += "`"${_}`"" | |
$_ = [Diagnostics.ProcessStartInfo]::new() | |
$_.CreateNoWindow = $False | |
$_.UseShellExecute = $False | |
$_.RedirectStandardInput = $True | |
$_.RedirectStandardOutput = $True | |
$_.RedirectStandardError = $True | |
$_.FileName = 'ssh' | |
#ArgumentList apparently isn't in my version of .NET/PowerShell | |
$_.Arguments = $args | |
$ssh = [Diagnostics.Process]::new() | |
$ssh.StartInfo = $_ | |
$started=[Collections.ArrayList]@() | |
$watch = { | |
if (![String]::IsNullOrEmpty($EventArgs.Data)) { | |
$Event.MessageData.Add($EventArgs.Data) | |
} | |
} | |
$out = Register-ObjectEvent ` | |
-InputObject $ssh ` | |
-Action $watch ` | |
-EventName 'OutputDataReceived' ` | |
-MessageData $started | |
$err = Register-ObjectEvent ` | |
-InputObject $ssh ` | |
-Action $watch ` | |
-EventName 'ErrorDataReceived' ` | |
-MessageData $started | |
$ssh.Start() | Out-Null | |
$ssh.BeginOutputReadLine() | |
$ssh.BeginErrorReadLine() | |
if (!$N) { | |
$ssh.StandardInput.Close() | |
} | |
try { | |
while (!$ssh.HasExited) { | |
while ($started.Count) { | |
if ($started[0] -eq 'SUCCESS') { | |
$started.RemoveAt(0) | |
Unregister-Event -SourceIdentifier $out.Name | |
Unregister-Event -SourceIdentifier $err.Name | |
$started | Out-Host | |
$started.Clear() | |
#if I attempt to `break` or `return` instead of `throw` we hang!! WHAT | |
#it has to do with `CreateNoWindow = $False` but if it's true ssh can no longer accept PIN code input (which is NOT stdin) | |
if ($N) { | |
'Call .StandardInput.Close() to close your session' | Out-Host | |
} | |
else { | |
'You can monitor when your session closes at .HasExited' | Out-Host | |
} | |
throw $ssh | |
} | |
$started[0] | Out-Host | |
$started.RemoveAt(0) | |
} | |
} | |
} | |
catch { | |
$_.TargetObject | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Works even without certs, ie it will still successfully ask for passwords or PINs [for PIV cards].
You can call with or without command like so;
For example if you just want to forward ports (equivalent to
-N
)$ssh = ssh-f -D 8080 remoteMachine
Then you can close it when you're done via
$ssh.StandardInput.Close()
Or if you're calling a long task to background
$ssh = 'cd projectDir/; ./buildAllAndRunTests.sh' | ssh-f remoteMachine
Where you can monitor whether it has exited via
$ssh.HasExited
You don't need to save it to a variable, you could simply
(ssh-d blah blah).Id
to print the PID to console and kill/observe it later, but unfortunately it will exit if you close the spawning terminal.It even works with
-v
and outputs any logs to console until connection is established, but after that point it will discard everything.You can edit the gist to forward this to a logfile if you'd like.