如何在PowerShell中转义特殊字符?

5
当我的PowerShell脚本运行时,会提示用户输入一个密码参数。该密码可以包含任意数量的特殊字符,如*\~;(%?.:@/。然后将该密码用作.exe命令的参数,但由于某些特殊字符没有正确转义,因此它经常不正确。
一个旧密码示例是$(?-.?-(。我需要转义的唯一字符是'(',我用'`('替换它以使其正常工作。但是,该密码现在已过期。新密码类似于*\~;~(%?.:@/ *注意:这些密码也混合了随机数字和字母,但已被编辑掉。
新密码中唯一不在旧密码中的字符是*\~;%:@/。是否有一种简便的方法来转义所有的字符并只接受任何用户输入?如果没有,那么有没有人愿意帮助我转义这些特殊字符?
param (
    [Parameter(Mandatory=$true)][string]$password
)

上述代码在脚本之前加了一个前缀,导致控制台提示用户输入。
Invoke-Expression -Command "<path_to_exe> -install $user $password"

这是使用密码参数的命令。


我尝试了许多在Stack Overflow、Reddit和其他各种编码论坛/博客上的建议,但都没有奏效。非常感谢任何帮助!


你是否有需要转义的完整字符列表? - Drew
请展示处理/设置密码的代码。我们无法在没有看到代码的情况下告诉您是否需要转义或如何转义。 - Ansgar Wiechers
@Drew *~;~(%?.:@/ 是我需要转义的完整字符列表。 - Enoch Chan
@param ( [Parameter(Mandatory=$true)][string]$password )上述代码为脚本添加前缀,导致控制台提示用户输入。Invoke-Expression -Command "<path_to_exe> -install $user $password"^这是使用该密码参数的命令 - Enoch Chan
1
不要使用“Invoke-Expression”。& 'C:\path\to\your.exe' -install $user $password 可以实现你想要的功能。 - Ansgar Wiechers
2个回答

8
你正在使用`Invoke-Expression`来调用外部程序:
没有理由这样做,而且通常应该避免使用`Invoke-Expression`:它会导致引号的问题(就像你的情况),更重要的是,它可能存在安全风险,并且通常有更好的解决方案。
顺便说一下:不幸的是,即使直接调用也可能存在关于空字符串参数和带有嵌入的`"`字符的引号挑战。请参考脚注[1]和这个答案。
如果你改为直接调用外部程序 - 就像任何Shell(包括PowerShell)设计的那样 - 你的问题很可能会消失。[1]
& <path_to_exe> -install $user $password

注意:PowerShell的调用运算符&仅在可执行文件的路径被引用(例如,"C:\Program Files\foo.exe")和/或通过变量引用指定(例如,$HOME\foo.exe)时需要;否则,您可以直接调用可执行文件(例如,要调用cmd.exe,可以使用类似于
cmd /c 'echo hi'的命令)。

分别的话,如果你确实需要转义字符集中的任何字符,请使用 -replace字符类[...]

注意:这对于传递参数来说不是必需的,无论是传递给上述外部程序还是 PowerShell 命令;然而,由于 PowerShell 对于传递给外部程序的参数值中嵌入的 " 字符处理有问题,您可能需要转义 " 字符(仅限于此),如 \"[1]

PS> 'a*b\c~d;e(f%g?h.i:j@k/l' -replace '[*\\~;(%?.:@/]', '`$&'
a`*b`\c`~d`;e`(f`%g`?h`.i`:j`@k`/l  # all chars. inside [...] were `-escaped

注意:由于\在字符类中具有特殊含义,因此必须转义为\\ - 其他所有字符均按原样使用。
有关-replace运算符的更多信息,请参阅this answer

[1] 有一个字符仍然会引起问题:嵌入的"。由于历史原因,PowerShell无法正确地将嵌入的"传递给外部程序,并且令人讨厌地要求在Windows PowerShell和PowerShell(Core)版本中进行手动\转义,直到v7.2.x版本为止 - 有关详细信息,请参阅this answer。 应用于您的解决方案:& <path_to_exe> -install $user ($password -replace '"', '\"')


5

使用以下方法可以使用你提到的转义前缀来转义字符。正常的转义前缀如下所示\。我将其设置为这种方式,以便您更容易地添加其他要转义的字符或更改转义前缀。

function Set-EscapeCharacters {
    Param(
        [parameter(Mandatory = $true, Position = 0)]
        [String]
        $string
    )
    $string = $string -replace '\*', '`*'
    $string = $string -replace '\\', '`\'
    $string = $string -replace '\~', '`~'
    $string = $string -replace '\;', '`;'
    $string = $string -replace '\(', '`('
    $string = $string -replace '\%', '`%'
    $string = $string -replace '\?', '`?'
    $string = $string -replace '\.', '`.'
    $string = $string -replace '\:', '`:'
    $string = $string -replace '\@', '`@'
    $string = $string -replace '\/', '`/'
    $string
}

$Password = Set-EscapeCharacters $Password

如果直接调用目标程序而不是通过 Invoke-Expression(需要的话)进行调用,我认为Enoch的逃逸问题会消失。除此之外,使用一个字符集([...])进行单个 -replace 操作更简单、更高效。小问题:[Regex]::Escape() 转义 regex 元字符,这与 PowerShell 无关。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接