Passing variable arguments to ShellExecute in vbscript

vbscript

I am trying to learn how to run a vbscript in elevated mode. I can't quite get this to work if there are arguments to the vbscript I am trying to run elevated.

Here is a simple example:

OSVersion.vbs

' Return a string indicating the operating system
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
   & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colOperatingSystems = objWMIService.ExecQuery _
   ("Select * from Win32_OperatingSystem")

'Wscript.echo Wscript.Arguments(0)
For Each objOperatingSystem in colOperatingSystems
   Wscript.StdOut.Write objOperatingSystem.Caption
   Wscript.StdOut.WriteBlankLines(1)
   Wscript.StdOut.Write "Version " & objOperatingSystem.Version
Next

RunElevated.vbs

' Run the script in elevated mode
'
' This will be needed to install programs into Program Files
prgName      = Wscript.Arguments.Item(0)
prgArgs      = ""
If Wscript.Arguments.Count > 1 Then
   For i = 1 To Wscript.Arguments.Count - 1
      prgArgs = prgArgs & " " & Wscript.Arguments.Item(i)
   Next
End If
Wscript.echo "Running: " & prgName & prgArgs
Set objShell = CreateObject("Shell.Application")
Set fso      = CreateObject("Scripting.FileSystemObject")
strPath      = fso.GetParentFolderName (WScript.ScriptFullName)
If fso.FileExists(strPath & "\" & prgName) Then
   objShell.ShellExecute "wscript.exe", _
     Chr(34) & strPath & "\" & prgName & Chr(34), _
     "", "runas", 1
Else
   Wscript.echo "Script file not found"
End If 

The OSVersion.vbs script runs fine:

cscript OSVersion.vbs
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

Microsoft Windows 7 Home Premium

Version 6.1.7601

Problem #1 When I try to run this elevated, nothing appears on stdout

C:\Users\ChemModeling\Documents\FreeThink\Java\install>cscript RunElevated.vbs OSVersion.vbs
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

Running: OSVersion.vbs

Problem #2 I cannot figure out how to include an argument to the script I am passing to RunElevated. I read that you should use a syntax like '"my parameters here"' so I tried this:

' Run the script in elevated mode
'
' This will be needed to install programs into Program Files
prgName      = Wscript.Arguments.Item(0)
prgArgs      = ""
If Wscript.Arguments.Count > 1 Then
   For i = 1 To Wscript.Arguments.Count - 1
      prgArgs = prgArgs & " " & Wscript.Arguments.Item(i)
   Next
End If
Wscript.echo "Running: " & prgName & prgArgs
Set objShell = CreateObject("Shell.Application")
Set fso      = CreateObject("Scripting.FileSystemObject")
strPath      = fso.GetParentFolderName (WScript.ScriptFullName)
If fso.FileExists(strPath & "\" & prgName) Then
   objShell.ShellExecute "wscript.exe", _
     Chr(39) & Chr(34) & strPath & "\" & prgName & prgArgs & Chr(34) & Chr(39), _
     "", "runas", 1
Else
   Wscript.echo "Script file not found"
End If 

If I run:

cscript RunElevated.vbs OSVersion.vbs Test
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

Running: OSVersion.vbs Test

I then get an error "There is no engine for file extension ".vbs Test".

Can anyone suggest what I need to change?

I have made some headway in resolving this problem-

I changed the first script to:

OSVersion.vbs

' Return a string indicating the operating system
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
   & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colOperatingSystems = objWMIService.ExecQuery _
   ("Select * from Win32_OperatingSystem")

'Wscript.echo Wscript.Arguments(0)
For Each objOperatingSystem in colOperatingSystems
   Wscript.Echo objOperatingSystem.Caption
   Wscript.Echo "Version " & objOperatingSystem.Version
Next

so I could actually see if something happened.

I changed the second script to:

' Run the script in elevated mode
'
' This will be needed to install programs into Program Files
prgName      = Wscript.Arguments.Item(0)
prgArgs      = ""
If Wscript.Arguments.Count > 1 Then
   For i = 1 To Wscript.Arguments.Count - 1
      prgArgs = prgArgs & " " & Wscript.Arguments.Item(i)
   Next
End If
Wscript.echo "Running: " & prgName & prgArgs
Set objShell = CreateObject("Shell.Application")
Set fso      = CreateObject("Scripting.FileSystemObject")
strPath      = fso.GetParentFolderName (WScript.ScriptFullName)
If fso.FileExists(strPath & "\" & prgName) Then
   objShell.ShellExecute "wscript.exe", _
     Chr(34) & strPath & "\" & prgName & Chr(34) & prgArgs, _
     "", "runas", 1
Else
   Wscript.echo "Script file not found"
End If 

and used: wscript RunElevated.vbs OSVersion.vbs Test

And now I see the information I am echoing in popups when the script runs.

So I am back to problem #1, I am starting a new shell to run in administrator mode, so if I switch to cscript and try to write the information to stdout or use Wscript.StdOut.Write, it will appear in the new shell and I will never see it, or at least that's what I believe the problem is.

Is there a standard way to address this issue?

Best Answer

Problem #1:

You're not seeing any output when you run your script elevated, because the RunElevated.vbs script re-launches your OSVersion.vbs script using WScript.exe. OSVersion.vbs uses Standard Input and Output which are only available from the console. Changing the command line in RunElevated.vbs to use cscript.exe instead of wscript.exe solves this problem. For more, check out my article Error Trapping and Capturing Third-Party Output in WSH.

Problem #2

It looks like your problem here is that you're mixing different kinds of quotes. A command should look like this:

"C:\path with spaces\command.exe" "parameter with spaces" "and another"

Try out these scripts.

RunElevated.vbs

' Run a script in Elevated Mode
strName      = WScript.Arguments.Item(0)
strArgs      = ""
If WScript.Arguments.Count > 1 Then
    For i = 1 To WScript.Arguments.Count - 1
        strArgs = strArgs & " " & WScript.Arguments.Item(i)
    Next
End If
WScript.echo "Running: ", strName, strArgs
Set objShell = CreateObject("Shell.Application")
Set objFso   = CreateObject("Scripting.FileSystemObject")
strPath      = objFso.GetParentFolderName(WScript.ScriptFullName)
strParams    = Chr(34) & strPath & "\" & strName & Chr(34)
If strArgs <> "" Then
    strParams = strParams & " " & Chr(34) & strArgs & Chr(34)
End If
If objFso.FileExists(strPath & "\" & strName) Then
     objShell.ShellExecute "cscript.exe", strParams, "", "runas", 1
Else
    WScript.echo "Script file not found"
End If

OSVersion.vbs

'Test passing arguments to launched script
If WScript.Arguments.Count > 0 Then
    For i = 0 To WScript.Arguments.Count - 1
        strArgs = Trim(strArgs & " " & WScript.Arguments.Item(i))
    Next
End If

' Return a string indicating the operating system
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colOperatingSystems = objWMIService.ExecQuery _
    ("Select * from Win32_OperatingSystem")

For Each objOperatingSystem in colOperatingSystems
    WScript.StdOut.Write objOperatingSystem.Caption
    WScript.StdOut.WriteBlankLines(1)
    WScript.StdOut.Write "Version " & objOperatingSystem.Version
    WScript.StdOut.WriteBlankLines(2)
Next

' Print out any passed arguments
WScript.StdOut.WriteBlankLines(2)
WScript.StdOut.Write strArgs
WScript.StdOut.WriteBlankLines(2)

' Keep the window from closing before you get a chance to read it
WScript.StdOut.Write "Press any key to continue "
strInput = WScript.StdIn.Read(1)

In order to capture the output, I would probably try a different approach using the WshShell Execute method. There are command line tools available such as Elevate or HStart that can launch command lines with elevated privileges. Here's how I would do it using Elevate.

' Run a script in Elevated Mode
strName      = WScript.Arguments.Item(0)
strArgs      = ""
If WScript.Arguments.Count > 1 Then
    For i = 1 To WScript.Arguments.Count - 1
        strArgs = strArgs & " " & WScript.Arguments.Item(i)
    Next
End If
WScript.echo "Running: ", strName, strArgs
Set WshShell = CreateObject("WScript.Shell")
Set objFso   = CreateObject("Scripting.FileSystemObject")
strPath      = objFso.GetParentFolderName(WScript.ScriptFullName)
strParams    = Chr(34) & strPath & "\" & strName & Chr(34)
If strArgs <> "" Then
    strParams = strParams & " " & Chr(34) & strArgs & Chr(34)
End If
If objFso.FileExists(strPath & "\" & strName) Then
    Set WshShellExec = WshShell.Exec("elevate cscript.exe " & strParams)

    Select Case WshShellExec.Status
        Case WshFinished
            strOutput = WshShellExec.StdOut.ReadAll
        Case WshFailed
            strOutput = WshShellExec.StdErr.ReadAll
    End Select
Else
    WScript.echo "Script file not found"
End If

WScript.echo strOutput