英文:
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-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:\\\""
- 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-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
) toobjShell.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
) 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-Wait
to it.- To also capture the exit code of the elevated process, additionally pass the
-PassThru
switch, which makesStart-Process
output a process-information object whose.ExitCode
property 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论