使用PowerShell命令通过VBS以提升权限运行批处理文件。

huangapple go评论63阅读模式
英文:

Launching a batch file with elevation via a PowerShell command from VBS

问题

有没有办法修复我脚本中的以下问题?

Set objShell = CreateObject("Wscript.Shell")
objShell.Run("powershell -Command Start-Process 'cmd' -Verb RunAs -ArgumentList '/c ""C:\Temp\CAL.bat""'")

错误:预期的 ')' 位置

我从https://stackoverflow.com/questions/11448365/running-powershell-from-vbs-with-command-as-parameter中获取了灵感,但我对这些事情的了解有限,无法帮助我解决问题。

英文:

any idea to fix the following that I have with my script?

Set objShell = CreateObject("Wscript.Shell")
 objShell.Run("powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c "C:\Temp\CAL.bat"'"")

Error: Expected ')'

I took the idea from https://stackoverflow.com/questions/11448365/running-powershell-from-vbs-with-command-as-parameter, but my little experience with these things does not help me.

答案1

得分: 1

  • 你需要先满足 VBScript 的语法规则:

    • 嵌套在 "..." 中的 " 字符必须被转义为 ""
  • 最终的字符串必须满足 PowerShell 的语法要求,它有两个方面:

    • 需要在传递给 powershell.exe,即 Windows PowerShell CLI 的 -Command (-c) 参数中 \ 转义 " 字符,以将其视为命令的文字部分。

      • 未转义的 " 字符在命令行上被视为纯语法功能,并且在命令行解析期间被移除。
    • 需要确保去除了 " 前的 \ 的字符串是有效的 PowerShell 语法。

  • 因此,使用 \""

    • 注意:如果通过 Start-Process 启动的进程是另一个以(可能是隐式的)-Command 启动的 PowerShell 实例(而不是像本例中的批处理文件),则需要在内部调用中进行两层转义:\\\""

因此:

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell -Command ""Start-Process cmd -Verb RunAs -ArgumentList '/c \""C:\Temp\CAL.bat\""'"""

注意:

  • 由于 objShell.Run() 不会通过 cmd.exe 调用,因此没有严格的需要将 -Command 参数整体包含在 ""..."" 中,这使上述命令更加可读。

  • 但是,不这样做会使被视为 -Command多个参数在空格规范化(多个空格被折叠为一个空格)时受到影响;尽管通常情况下这不是问题,但它可能是问题,特别是如果这些多空格运行必须作为 PowerShell 应该视为字符串字面量的一部分而保留。

  • 在您的具体情况下,由于您正在调用批处理文件,因此您可以进一步简化命令:Start-Process 直接接受批处理文件路径作为可执行文件,即作为(位置上隐含的)-FilePath 参数的参数;因此,省略所有可选引号,您的特定命令的最简单表达方式是:

    Set objShell = CreateObject("Wscript.Shell")
    objShell.Run "powershell -Command Start-Process C:\Temp\CAL.bat -Verb RunAs"
    

---

如果您希望整个调用**以不可见方式运行**,有两个方面:

* 要隐藏*立即*启动的进程,将第二个参数 (`intWindowStyle`) 传递给 [`objShell.Run()`](https://learn.microsoft.com/en-us/previous-versions//d5fk67ky(v=vs.85)) 的值设置为 `0`。

* 要隐藏通过 `Start-Process` 间接启动的进程,传递 `-WindowStyle Hidden` 给它。

因此:

```vbscript
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell -Command Start-Process C:\Temp\CAL.bat -Verb RunAs -WindowStyle Hidden", 0

此外,如果您希望进程同步方式运行**,即希望 object.Run() 调用等待所有启动的进程完成:

  • true 作为第三个参数 (bWaitOnReturn) 传递给 objShell.Run(),以使立即启动的进程执行同步。

    • 注意:这样做会使 object.Run() 返回该进程的退出代码;要在 VBScript 代码中捕获它,将参数放在 (...) 中,并将返回值赋给一个变量:

      exitCode = objShell.Run(..., ..., true)
      
  • 要同时同步执行间接启动的进程,即通过 Start-Process -Verb RunAs 启动的提权进程,将 -Wait 传递给它。

    • 要同时捕获提权进程的退出代码,另外传递 -PassThru 开关,使 Start-Process 输出一个包含 .ExitCode 属性的进程信息对象,您可以访问它,并将其传递给 exit

因此,如果您希望结合不可见和同步执行,以及捕获退出代码

Set objShell = CreateObject("Wscript.Shell")
exitCode = objShell.Run("powershell -Command exit (Start-Process C:\Temp\CAL.bat -Verb RunAs -WindowStyle Hidden -Wait -PassThru).ExitCode", 0, true)
英文:
  • You need to satisfy VBScript's own syntax rules first:

    • " chars. embedded inside "..." must be escaped as ""
  • The resulting string must satisfy PowerShell's syntax, which has two aspects:

    • Needing to \-escape " chars. that should be considered a verbatim part of the command(s) passed to the -Command (-c) parameter of powershell.exe, the Windows PowerShell CLI.

      • Unescaped " chars. are assumed to have purely syntactic function on the command line, and are removed during command-line parsing.
    • Needing to ensure that the resulting string - with the \ before " removed - is valid PowerShell syntax.

  • Thus, use \""

    • Note: In case the process launched via Start-Process is another PowerShell instance launched with (possibly implied) -Command (rather than a batch file, as in this case), two layers of escaping are required in the inner call: \\\""

Therefore:

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell -Command ""Start-Process cmd -Verb RunAs -ArgumentList '/c \""C:\Temp\CAL.bat\""'"""

Note:

  • Since objShell.Run() does not call via cmd.exe, there is no strict need to enclose the -Command argument in ""..."" overall, which makes the above command a bit more readable.

  • However, not doing so subjects what are then technically multiple arguments to -Command to whitespace normalization (runs of multiple spaces are folded into a single space); while that is typically not a problem, it can be, namely if such multi-space runs must be preserved as part of what PowerShell should see as a string literal.

  • In your specific case, since you're calling a batch file, you can further simplify your command for that reason: Start-Process accepts batch-file paths directly as executables, i.e. as the arguments to the (positionally implied) -FilePath parameter; therefore, omitting all optional quoting, the simplest formulation of your specific command is:

    Set objShell = CreateObject("Wscript.Shell")
    objShell.Run "powershell -Command Start-Process C:\Temp\CAL.bat -Verb RunAs"
    

If you want the entire invocation to run invisibly, there are two aspects:

  • To hide the immediately launched process, pass 0 as the value of the 2nd parameter (intWindowStyle) to objShell.Run().

  • To hide the indirectly launched process, via Start-Process, pass -WindowStyle Hidden to it.

Therefore:

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell -Command Start-Process C:\Temp\CAL.bat -Verb RunAs -WindowStyle Hidden", 0

Separately, if you want the processes to run synchronously, i.e. if you want the object.Run() call to wait until all launched processes have finished:

  • Pass true as the value of the 3rd parameter (bWaitOnReturn) to objShell.Run() to make the immediately launched process execution synchronous.

    • Note: Doing so makes object.Run() return the exit code of that process; to capture it in VBScript code, use (...) around the arguments and assign the return value to a variable:

      exitCode = objShell.Run(..., ..., true)
      
  • To also execute the indirectly launched process synchronously, i.e. the elevated one launched via Start-Process -Verb RunAs, pass -Wait to it.

    • To also capture the exit code of the elevated process, additionally pass the -PassThru switch, which makes Start-Process output a process-information object whose .ExitCode property you can access, and which you can pass to exit

Therefore, if you want to combine invisible and synchronous execution, as well as capture the exit code:

Set objShell = CreateObject("Wscript.Shell")
exitCode = objShell.Run("powershell -Command exit (Start-Process C:\Temp\CAL.bat -Verb RunAs -WindowStyle Hidden -Wait -PassThru).ExitCode", 0, true)

huangapple
  • 本文由 发表于 2023年6月30日 05:21:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76584670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定