Search code examples
powershellsyntaxwinscp

Convert a batch-file command with complex arguments to PowerShell


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.


Solution

  • Whenever I have to invoke an executable from PowerShell, I always pass the parameters as a list, like below. I also use single quote marks, unless I'm actually substituting variables, in which case I have to use the double quotation marks.

     & SomeUtility.exe @('param1','param2',"with$variable")
    

    It gets a little tricky when there are spaces in the parameters, since you may have to provide quotation marks so that the utility can properly parse the command.

    Your example is even more tricky, since WinScp wants the argument of the /command parameter enclosed in quotation marks, and any strings inside enclosed in double quotation marks. All of that needs to be preserved, because of WinScp. I believe the following would work. I've broken up the parameters into multiple lines for readability. I'm also assuming that you've successfully populated your $winscp, $outfile, and $basename variables.

    $params = @(
      '/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"'
    )
    
    & $winscp $params
    

    Note the parentheses around the fifth parameter; this is due to the string concatenation operations there. (Without the parentheses, each operand would have been added to the list separately -- you can confirm this by looking at $params.Count.) Also keep in mind that you will need quotation marks around your log file path if you ever have to change it to something with spaces.