Assuming a file named script.ps1
in the current directory, and arguments foo
and bar
(alternatively, remove $PWD
below and specify the full script file path); -NoExit
keeps the elevated console window that is created open after running the script:
strCommand = "powershell.exe -c Start-Process -Verb RunAs powershell.exe \"" -ExecutionPolicy Unrestricted -NoExit -f `\""$PWD\script.ps1`\"" foo bar \"""
Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)
Note the need to call the Windows PowerShell CLI, powershell.exe
, twice, nested:
First, in order to be able to run the PowerShell-internal Start-Process
cmdlet with -Verb RunAs
so as to create an elevated (run-as-admin) process, which invariably runs in a new console window. (Note that WshShell.Exec()
itself runs asynchronously and provides no direct feedback.)
- Note that this will present the UAC security dialog to confirm the intent to create an elevated process, and that this dialog can by design only be responded to interactively.
Second, as the process to be elevated in order to invoke the target script elevated.
- Caveat: The elevated target process will see
C:\Windows\System32
as its working directory, not the caller's. To use the caller's working directory, you'd have to switch from a -file
(-f
)-based call to a -command
(-c
)-based one and execute a Set-Location
statement first, which can notably also change how pass-through arguments for the script are interpreted; see this answer.
This complicates quoting, and requires requires that the nested call's "
characters be seen as `\"
(represented as `\""
inside a VBScript string literal) on the outer call's command line, and the outer call's "
as \"
(\""
in VBScript).
See this answer for how to construct such a command line for use with many parameters (arguments) algorithmically, via a dictionary of parameter name-value pairs.