英文:
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 ofpowershell.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.
- Unescaped
-
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-Processis 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:\\\""
- Note: In case the process launched via
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 viacmd.exe, there is no strict need to enclose the-Commandargument in""...""overall, which makes the above command a bit more readable. -
However, not doing so subjects what are then technically multiple arguments to
-Commandto 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-Processaccepts batch-file paths directly as executables, i.e. as the arguments to the (positionally implied)-FilePathparameter; 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
0as the value of the 2nd parameter (intWindowStyle) toobjShell.Run(). -
To hide the indirectly launched process, via
Start-Process, pass-WindowStyle Hiddento 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
trueas the value of the 3rd parameter (bWaitOnReturn) toobjShell.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-Waitto it.- To also capture the exit code of the elevated process, additionally pass the
-PassThruswitch, which makesStart-Processoutput a process-information object whose.ExitCodeproperty you can access, and which you can pass toexit
- To also capture the exit code of the elevated process, additionally pass the
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论