gpt4 book ai didi

powershell - PowerShell的命令行转义单引号

转载 作者:行者123 更新时间:2023-12-02 23:36:35 24 4
gpt4 key购买 nike

我有一个Windows应用程序,在发生事件时,它会调用如下命令:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x' -data '%y'"

name参数有时包含 '。有可能以某种方式逃脱吗?

最佳答案

实际上,这比您想象的要复杂得多。在从cmd传递到PowerShell的字符串中转义嵌套的引号是一个主要的麻烦。使得这一问题特别棘手的是,您需要在传递给PowerShell脚本参数的单引号内,将传递给powershell.exe的带引号的参数中由cmd扩展的变量替换。 AFAIK cmd甚至没有用于基本字符串替换的任何本机功能,因此您需要PowerShell来为您进行替换。

如果 -data 参数(cmd变量 x 所包含的参数)的参数不一定需要用单引号引起来,那么最简单的方法就是将其双引号,这样 x 的值根本不需要转义。我说“最简单”,但是即使这样也有些棘手。正如Vasili Syrakis指出的那样,^通常是cmd中的转义字符,但是要在(双引号)字符串中转义双引号,则需要使用\。因此,您可以这样编写批处理命令:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name \"%x%\" -data '%y%'"
这会将以下命令传递给PowerShell:

G:\test.ps1 -name "value of x, which may contain 's" -data 'value of y'

但是,如果 x 也可以包含在PowerShell插值字符串中为特殊字符的字符( "$`),那么它将变成 LOT 更加复杂。问题是 %x 是一个cmd变量,在PowerShell有机会接触它之前,该变量会被cmd扩展。如果在传递给powershell.exe的命令中将单引号引起来,并且它包含单引号,那么您将为PowerShell session 提供一个字符串,该字符串将尽早终止,因此PowerShell没有机会执行任何操作。操作就可以了。以下内容显然不起作用,因为在替换任何内容之前,必须向 -replace 运算符提供有效的字符串:
'foo'bar' -replace "'", "''"

另一方面,如果将其双引号,那么PowerShell会在对该字符串执行任何替换之前先对字符串进行插值,因此,如果该字符串包含任何特殊字符,则会先对其进行解释,然后才能通过替换对它们进行转义。我在上下搜索其他以内联方式引用文字字符串的方式(与perl的 q // 等效,在该方式中,除了选择的分隔符之外,没有其他要转义的内容),但似乎没有任何内容。

因此,剩下的唯一解决方案是使用here字符串,该字符串需要多行参数。在批处理文件中这很棘手,但是可以做到:
setlocal EnableDelayedExpansion
set LF=^


set pscommand=G:\test.ps1 -name @'!LF!!x!!LF!'@ -data '!y!'
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "!pscommand!"
  • 这假定在批处理文件中较早设置了 x 。如果您的应用只能向cmd发送单行命令,则需要将以上内容放入批处理文件中,并在开头添加以下两行:
    set x=%~1
    set y=%~2

    然后像这样调用批处理文件:
    path\test.bat "%x%" "%y%"
    ~去除命令行参数周围的引号。您需要使用引号将变量中包含空格,但是引号也将添加到变量值中。批处理是那样愚蠢的。
  • 要求set LF=^之后的两个空白行。

  • 这将处理单引号,该单引号也将按字面意义解释 x 值中的所有其他字符,但有一个异常(exception):双引号。不幸的是,如果双引号可能是您在注释中指示的值的一部分,那么我认为如果不使用第三方实用程序,这个问题是无法解决的。原因是,如上所述,批处理没有执行字符串替换的本机方法,并且在PowerShell看到之前,cmd会扩展 x 的值。

    顺便说一句...好问题!

    更新:

    实际上,事实证明可以在cmd中执行静态字符串替换。邓肯(Duncan)添加了一个答案,展示了如何做到这一点。这有点令人困惑,所以我将详细说明Duncan解决方案中发生的事情。

    这个想法是 %var:hot=cold%扩展为变量 var 的值,所有 hot都替换为 cold:
    D:\Scratch\soscratch>set var=You're such a hot shot!

    D:\Scratch\soscratch>echo %var%
    You're such a hot shot!

    D:\Scratch\soscratch>echo %var:hot=cold%
    You're such a cold scold!

    因此,在命令中(为清楚起见,根据邓肯的回答进行了修改以与OP的示例保持一致):
    powershell G:\test.ps1 -name '%x:'=''%' -data '%y:'=''%'

    变量 x y 中的所有 '都替换为 '',命令扩展为
    powershell G:\test.ps1 -name 'a''b' -data 'c''d'

    让我们分解其中的关键元素 '%x:'=''%':
  • 开头和结尾的两个'是传递给PowerShell的显式外引号,以对参数进行引用,即,OP与%x
  • 相同的单引号
  • :'=''是字符串替换,指示应将'替换为''
  • %x:'=''%扩展为变量 x 的值,其中'替换为'',即a''b
  • 因此,整个过程扩展为'a''b'

  • 与上面的解决方法相比,此解决方案更简单地转义了变量值中的单引号。但是,OP在更新中指示该变量可能还包含双引号,并且到目前为止,该解决方案仍未将 x 中的双引号传递给PowerShell-在PowerShell接收命令之前,cmd仍会将其删除。

    好消息是,使用cmd字符串替换方法,这是可以克服的。在设置了 x 的初始值后,执行以下cmd命令:
  • '替换'',以转义PowerShell的单引号:
    set x=%x:'=''%
  • "替换\",以转义cmd的双引号:
    set x=%x:"=\"%

    这两个任务的顺序无关紧要。
  • 现在,可以使用OP首先使用的语法来调用PowerShell脚本(删除powershell.exe的路径以使其全部适合一行):
    powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x' -data '%y'"

  • 同样,如果应用程序只能向cmd发送单行命令,则可以将这三个命令放置在批处理文件中,并且应用程序可以调用该批处理文件并传递变量,如上所示(我原始答案的第一个项目符号) 。

    需要注意的一个有趣点是,如果用 "替换 \"是内联而不是使用单独的 set 命令完成的,即使字符串替换在双引号中,您也不会转义 " s字符串,即像这样:
    powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x:"=\"' -data '%y'"

    ... 而不是像这样:
    powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x:\"=\\"' -data '%y'"

    关于powershell - PowerShell的命令行转义单引号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20958388/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com