将具有复杂参数的批处理文件命令转换为PowerShell
我在.bat中有以下内容,即(这是有效的): 我尝试将其复制到powershell脚本中,如下所示:将具有复杂参数的批处理文件命令转换为PowerShell,powershell,syntax,winscp,Powershell,Syntax,Winscp,我在.bat中有以下内容,即(这是有效的): 我尝试将其复制到powershell脚本中,如下所示: & $winscp "/ini=nul" ` "/log=C:\TEMP\winscplog.txt" ` "/command" 'open sftp://goofy:changeme@10.61.10.225/ -hostkey="ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6
& $winscp "/ini=nul" `
"/log=C:\TEMP\winscplog.txt" `
"/command" 'open sftp://goofy:changeme@10.61.10.225/ -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"
"/command" 'open sftp://goofy:changeme@10.61.10.225/ -hostkey=""ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d""' `
当我运行.bat脚本时,文件将上载
运行.ps1脚本时,我得到的主机密钥与配置的密钥ssh rsa不匹配
我怀疑我在powershell中没有正确格式化该命令,并且在winscp看到该命令时,主机密钥已被损坏
我检查了日志,显示的只是主机的主机密钥。它没有显示我正在使用的键。我改变了我的主机,并注意到它没有出现在日志中,从而证实了这一点。我比较了.bat和.ps1之间的日志,差别是ps1终止时出现了上面提到的错误
winscp是一个sftp实用程序。我运行了您的代码(当然是为了使用我自己的服务器而修改的),并获得了以下日志:
. 2017-03-04 15:32:24.387 Command-line: "C:\Program Files (x86)\WinSCP\WinSCP.exe" /ini=nul /log=C:\TEMP\winscplog.txt /command "open sftp://goofy:***@10.61.10.225/ -hostkey=ssh-rsa" 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d"" exit
. 2017-03-04 15:32:24.388 Time zone: Current: GMT-6, Standard: GMT-6 (Central Standard Time), DST: GMT-5 (Central Daylight Time), DST Start: 3/12/2017, DST End: 11/5/2017
. 2017-03-04 15:32:24.388 Login time: Saturday, March 4, 2017 3:32:24 PM
. 2017-03-04 15:32:24.388 --------------------------------------------------------------------------
. 2017-03-04 15:32:24.388 Script: Retrospectively logging previous script records:
> 2017-03-04 15:32:24.388 Script: open sftp://goofy:***@10.61.10.225/ -hostkey=ssh-rsa
. 2017-03-04 15:32:24.388 --------------------------------------------------------------------------
请注意,在第一行中,它是如何在-hostkey=ssh rsa
之后立即插入双引号的,在最后一行中,-hostkey
参数是如何从我们预期的参数截断的
在将-hostkey
参数周围的内部双引号加倍后,我能够成功连接,如下所示:
& $winscp "/ini=nul" `
"/log=C:\TEMP\winscplog.txt" `
"/command" 'open sftp://goofy:changeme@10.61.10.225/ -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"
"/command" 'open sftp://goofy:changeme@10.61.10.225/ -hostkey=""ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d""' `
每当我必须从PowerShell调用可执行文件时,我总是将参数作为列表传递,如下所示。我也使用单引号,除非我实际上在替换变量,在这种情况下,我必须使用双引号
& SomeUtility.exe @('param1','param2',"with$variable")
当参数中有空格时,这会变得有点棘手,因为您可能必须提供引号,以便实用程序能够正确地解析命令
您的示例甚至更复杂,因为WinScp希望/command
参数的参数用引号括起来,而其中的任何字符串都用双引号括起来。由于WinScp,所有这些都需要保留。我相信以下方法会奏效。为了便于阅读,我将参数分成了多行。我还假设您已经成功地填充了$winscp
、$outfile
和$basename
变量
$params = @(
'/ini=nul',
'/log=C:\TEMP\winscplog.txt',
'/command',
'"open scp://goofy:changeme@10.61.10.225/ -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
注意第五个参数周围的括号;这是由于那里的字符串连接操作造成的。(如果没有括号,每个操作数都会被单独添加到列表中——您可以通过查看$params.Count
)来确认这一点。此外,请记住,如果必须将日志文件路径更改为带空格的路径,则需要在其周围加上引号。注意:
- 是这种情况下的最佳解决方案
- 此答案通常讨论如何将为
编写的命令行转换为PowerShellcmd.exe
将
cmd.exe
(批处理文件)命令行转换为PowerShell非常棘手-非常棘手,以至于PSv3伪参数中的
已介绍:
它的目的是允许您将--%
之后的所有内容按原样传递给目标程序,以便控制精确的引用-除了cmd.exe
-style%…%
-style环境变量引用仍然由PowerShell扩展
但是,-->%
有许多严重的限制,下面将讨论这些限制,并且它的用途仅限于Windows,因此应将其视为最后的手段
替代方法是使用PSv3+(使用PSv5+中的install Module Native
安装,它提供了两个命令,可在内部补偿PowerShell的所有参数传递和cmd.exe
的参数解析异常:
- 函数
,您可以在调用外部程序(包括ie
)之前使用它,只允许您使用PowerShell的语法,而不必担心参数传递问题;e、 g:cmd.exe
# Without `ie`, this command would malfunction. 'a"b' | ie findstr 'a"b'
- 函数
(ins
)函数允许您按原样重用为Invoke NativeShell
编写的命令行,并作为单个字符串传递;与cmd.exe
不同,这还允许您通过PowerShell(-->%
)在命令行中嵌入PowerShell变量和表达式:“…”
-%
必须遵循要调用的外部实用程序的名称/路径(它不能是命令行上的第一个标记),因此,如果通过[environment]变量传递,则必须使用PowerShell语法定义和引用实用程序可执行文件(路径)-->%
只支持一个命令,同一行上未加引号的-%
、
或|
如果存在,则隐式结束;这允许您将此类命令与其他命令进行管道/链接&
- 但是,使用
不支持无条件地在同一行上放置另一个命令;代码>是逐字传递的
读取(最多)到行尾,因此使用行连续字符将命令分散到多行。不受支持。[2]-->%
- 但是,使用
- 除了
环境变量引用之外,您不能在命令中嵌入任何其他动态元素;也就是说,不能使用常规PowerShell变量引用或表达式%…%
- 不支持将
字符转义为%%
(在批处理文件中可以使用的方法)<如果%%
引用已定义的环境变量,则代码>%%标记将始终展开(如果不是,则标记按原样传递)
- 不支持将
- 除了环境变量引用以外,不能嵌入
# 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:changeme@10.61.10.225/ -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"
try { # Load WinSCP .NET assembly Add-Type -Path 'WinSCPnet.dll' # Setup session options $sessionOptions = New-Object WinSCP.SessionOptions -Property @{ Protocol = [WinSCP.Protocol]::Sftp HostName = '10.61.10.225' UserName = 'goofy' Password = 'changeme' SshHostKeyFingerprint = 'ssh-rsa 2048 d4:1c:1a:4c:c3:60:d5:05:12:02:d2:d8:d6:ae:6c:5d' } $session = New-Object WinSCP.Session try { # Connect $session.Open($sessionOptions) # Upload files $transferOptions = New-Object WinSCP.TransferOptions $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary $transferResult = $session.PutFiles($outfile, "/home/public/somedir/somesubdir/$basename", $false, $transferOptions) # Throw on any error $transferResult.Check() # Print results foreach ($transfer in $transferResult.Transfers) { Write-Host ("Upload of {0} succeeded" -f $transfer.FileName) } } finally { # Disconnect, clean up $session.Dispose() } exit 0 } catch [Exception] { Write-Host ("Error: {0}" -f $_.Exception.Message) exit 1 }