I have the following in .bat that is (this works):
"%winscp%" /ini=nul ^
/log=C:\TEMP\winscplog.txt ^
/command "open scp://goofy:[email protected]/ -hostkey=""ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d""" ^
"put ""%outfile%"" /home/public/somedir/somesubdir/%basename%" ^
"exit"
I have tried to duplicate that into a powershell script like this:
& $winscp "/ini=nul" `
"/log=C:\TEMP\winscplog.txt" `
"/command" 'open sftp://goofy:[email protected]/ -hostkey="ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d"' `
"put `"" + $outfile + "`" /home/public/somedir/somesubdir/" + $basename `
"exit"
When I run the .bat script the file will upload.
When I run the .ps1 script I get Host key does not match configured key ssh-rsa
I suspect that I have not formatted the command properly in powershell and the hostkey is getting mangled by the time winscp sees it.
I checked the log and all that is shown is the hostkey from the host. It does not show the key I am using. I confirmed that by changing my host and noting that it did not show up in the log. I compared the log between .bat and .ps1 and the difference is ps1 terminates with the error noted above.
winscp is a sftp utility.
Note:
JamesQMurphy's helpful answer is the best solution in this case.
This answer generally discusses translating command lines written for cmd.exe
to PowerShell.
Translating cmd.exe
(batch-file) command lines to PowerShell is tricky - so tricky, that in PSv3 pseudo-parameter
--%
, the stop-parsing token, was introduced:
Its purpose is to allow you to pass everything that comes after --%
as-is through to the target program, so as the control the exact quoting - except that cmd.exe
-style %...%
-style environment-variable references are still expanded by PowerShell[1].
However, --%
comes with many severe limitations - discussed below - and its usefulness is limited to Windows, so it should be considered a last resort;
An alternative is to use the PSv3+ Native
module (install with Install-Module Native
from the PowerShell Gallery in PSv5+), which offers two commands that internally compensate for all of PowerShell's argument-passing and cmd.exe
's argument-parsing quirks:
Function ie
, which you prepend to any call to an external program, including cmd.exe
, allows you to use only PowerShell's syntax_, without having to worry about argument-passing problems; e.g.:
# Without `ie`, this command would malfunction.
'a"b' | ie findstr 'a"b'
Function ins
(Invoke-NativeShell
) function allows you to reuse command lines written for cmd.exe
as-is, passed as a single string; unlike --%
, this also allows you to embed PowerShell variables and expressions in the command line, via a PowerShell expandable string ("..."
):
# Simple, verbatim cmd.exe command line.
ins 'ver & whoami'
# Multi-line, via a here-string.
ins @'
dir /x ^
c:\
'@
# With up-front string interpolation to embed a PowerShell var.
$var='c:\windows'; ins "dir /x `"$var`""
--%
--%
must follow the name/path of the external utility to invoke (it can't be the first token on the command line), so that the utility executable (path) itself, if passed by [environment] variable, must be defined and referenced using PowerShell syntax.
--%
supports only one command, which an unquoted |
, ||
or &&
on the same line, if present, implicitly ends; that allows you to pipe / chain such a command to / with other commands.
However, using ;
in order to unconditionally place another command on the same line is not supported; the ;
is passed through verbatim.
--%
reads (at most) to the end of the line so spreading a command across multiple lines with line-continuation chars. is NOT supported.[2]
Other than %...%
environment-variable references, you cannot embed any other dynamic elements in the command; that is, you cannot use regular PowerShell variable references or expressions.
%
characters as %%
(the way you can do inside batch files) is not supported; %<name>%
tokens are invariably expanded, if <name>
refers to a defined environment variable (if not, the token is passed through as-is).Other than %...%
environment-variable references, you cannot embed any other dynamic elements in the command; that is, you cannot embed regular PowerShell variable references or expressions.
You cannot use stream redirections (e.g., >file.txt
), because they are passed verbatim, as arguments to the target command.
| Set-Content file.txt
instead, but there is no direct PowerShell workaround for stderr output.cmd
, you can let cmd
handle the (stderr) redirection (e.g., cmd --% /c nosuch 2>file.txt
)Applied to your case, this means:
%winscp%
must be translated to its PowerShell equivalent, $env:winscp
, and the latter must be prefixed with &
, PowerShell's call operator, which is required when invoking external commands that are specified by variable or quoted string.& $env:winscp
must be followed by --%
to ensure that all remaining arguments are passed through unmodified (except for expansion of %...%
variable references).--%
, but must be on a single line.Therefore, the simplest approach in your case - albeit at the expense of having to use a single line - is:
# Invoke the command line with --%
# All arguments after --% are used as-is from the original command.
& $env:winscp --% /ini=nul /log=C:\TEMP\winscplog.txt /command "open scp://goofy:[email protected]/ -hostkey=""ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d""" "put ""%outfile%"" /home/public/somedir/somesubdir/%basename%" "exit"
[1] Note that, despite the cmd.exe
-like syntax, --%
also works on Unix-like platforms in PowerShell Core (macOS, Linux), but is of very limited use there: unlike with native shells such as bash
there, --%
only works with double-quoted strings ("..."
); e.g., bash --% -c "hello world"
works, but bash --% -c 'hello world'
doesn't - and the usual shell expansions, notably globbing, aren't supported - see this GitHub issue.
[2] Even `
, PowerShell's own line-continuation character, is treated as a pass-through literal. cmd.exe
isn't even involved when you use --%
(unless you explicitly use cmd --% /c ...
), so its line-continuation character, ^
, cannot be used either.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With