powershell.exe start-process -关于使用Verb选项时的“\”

powershell.exe start-process -About "\" when using the Verb option

感谢您的帮助。
我在 Windows 10 命令提示符下使用 Powershell 并尝试以管理权限执行命令。
当我尝试以下三个 a、b 和 c 时,我无法像我想的那样从“RunAs”开始。
有谁知道如何解决这个问题?

(a) 可以执行成功。参数也正确传递。
powershell.exe start-process -FilePath 'TestEnv.cmd' -ArgumentList '\"a\" \"B C\" \"d\"' -Verb Open

(b) 在 UAC 确认后不启动。
powershell.exe start-process -FilePath 'TestEnv.cmd' -ArgumentList '\"a\" \"B C\" \"d\"' -Verb RunAs

(c) 可以调用,但是“B C”参数没有体现在“双引号”参数中,单独识别“B C”。
powershell.exe start-process -FilePath 'TestEnv.cmd' -ArgumentList '"a" "B C" "d"' -Verb RunAs

翻译成www.DeepL.com/Translator(免费版)

tl;dr

REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k {0} \"a\" \"B C\" \"d\"' -f ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))
  • /k替换为/c,使新的window在批处理文件退出时自动关闭。

  • 批处理文件的工作目录C:\Windows\System32

如果你也想保证批处理文件在调用者当前目录执行:

REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k cd \"{0}\" ^&^& {1} \"a\" \"B C\" \"d\"' -f $PWD.ProviderPath, ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))

继续阅读以获得解释。


主要问题是:

  • 当您将批处理文件路径 直接 作为可执行文件传递给 Start-Process -Verb RunAs 时,似乎有传递包含双引号的参数列表时出现问题 (") - 我不知道原因,但问题出现在下面层PowerShell,在底层 System.Diagnostics.ProcessStartInfo .NET API or possibly even in the underlying ShellExecuteExe WinAPI 函数中。

  • (如果您需要 没有 个参数,或者 none 个参数需要 ",您 可以 直接将批处理文件路径作为可执行文件传递;默认情况下,因为底层可执行文件是 cmd.exe,位于 C:\Windows\System32C:\Windows\System32 成为工作目录,您可以使用 -WorkingDirectory 覆盖,但请注意,如果它位于其他位置,则必须使用(可能是相对的) 路径 引用批处理文件。)

解决方法

  • 不是直接使用批处理文件路径作为可执行文件来启动,而是使用cmd.exe作为可执行文件,并通过批处理-文件路径及其所有参数作为 /c 选项的参数(或 /k,如果你想保持新的 window 打开)。

  • 不幸的是,-Verb Runascmd.exe 总是使用C:\Windows\System32作为新进程的工作目录——传递然后忽略带有 -WorkingDirectory 参数的启动目录。

    • 这同样适用于 powershell.exe,但奇怪的是,不是 pwsh.exe (PowerShell [Core] v6+) 和 。基于 NET 的 可执行文件,其中 (a) 默认保留调用者的工作目录 并且 (b) 遵守 -WorkingDirectory 参数。
  • 因此,如果您的 TestEnv.cmd 批处理文件位于 当前 目录中 - 而不是 [=39= 中列出的目录] 环境变量 ($env:PATH) - 您必须将批处理文件的 完整路径 传递给 cmd.exe,您可以使用 Convert-Path.[=64 确定=]

    • 注意:如果你的批处理文件PATH,那么可以说,这一步是不需要的。

    • 不幸的是,如果批处理文件的完整路径包含空格,则需要另一个解决方法:因为"..."-莫名其妙地包含批处理文件路径失败,必须^-转义各个空格。

来自 inside PowerShell 这意味着您的命令必须如下所示(注意我使用 /k 来保持新的 window 打开,用于诊断目的;使用 /c 在批处理文件退出时自动关闭 window:

# From inside PowerShell:
Start-Process cmd.exe -Verb RunAs (
  '/k {0} "a" "B C" "d"' -f ((Convert-Path 'TestEnv.cmd') -replace ' ', '^ ')
)

警告:由于正在调用 cmd.exe,因此 C:\Windows\System32 是工作目录。
如果你还想确保批处理文件在调用者的当前目录中执行,你必须在前面加上一个cd命令:

# From inside PowerShell:
Start-Process cmd.exe -Verb RunAs (
  '/k cd "{0}" && {1} "a" "B C" "d"' -f $PWD.ProviderPath, ((Convert-Path 'TestEnv.cmd') -replace ' ', '^ ')
)

cmd.exe(命令提示符)/批处理文件 调用此 ,通过 Windows PowerShell's CLI, powershell.exe (note that in PowerShell [Core] v6+ it is now pwsh),增加额外的复杂性:

  • " 个字符。必须转义为 \",以便 PowerShell 将它们识别为要执行的命令的一部分,而不是 CLI 参数周围的语法引号。

  • ^ 必须转义为 ^^,并且在下面的第二个命令中,& 转义为 ^& 以防止 cmd.exe从解释这些字符(前面)。

REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k {0} \"a\" \"B C\" \"d\"' -f ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))

如果你也想保证批处理文件在调用者当前目录执行:

REM From cmd.exe (Command Prompt) / a batch file:
powershell.exe -c Start-Process cmd.exe -Verb RunAs ('/k cd \"{0}\" ^&^& {1} \"a\" \"B C\" \"d\"' -f $PWD.ProviderPath, ((Convert-Path 'TestEnv.cmd') -replace ' ', '^^ '))