【问题标题】:Passing variable arguments to ShellExecute in vbscript在 vbscript 中将变量参数传递给 ShellExecute
【发布时间】:2012-07-21 22:33:20
【问题描述】:

我正在尝试学习如何在提升模式下运行 vbscript。如果我尝试提升的 vbscript 存在参数,我将无法完全正常工作。

这是一个简单的例子:

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 

OSVersion.vbs 脚本运行良好:

cscript OSVersion.vbs Microsoft (R) Windows 脚本宿主版本 5.8 版权所有 (C) 微软公司。保留所有权利。

Microsoft Windows 7 家庭高级版

版本 6.1.7601

问题 #1 当我尝试运行此提升程序时,stdout 上没有显示任何内容

C:\Users\ChemModeling\Documents\FreeThink\Java\install>cscript RunElevated.vbs OSVersion.vbs Microsoft (R) Windows 脚本宿主版本 5.8 版权所有 (C) 微软公司。保留所有权利。

运行:OSVersion.vbs

问题 #2 我无法弄清楚如何在传递给 RunElevated 的脚本中包含参数。我读到你应该使用像“我的参数在这里”这样的语法,所以我尝试了这个:

' 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 

如果我跑:

cscript RunElevated.vbs OSVersion.vbs 测试 Microsoft (R) Windows 脚本宿主版本 5.8 版权所有 (C) 微软公司。保留所有权利。

正在运行:OSVersion.vbs 测试

然后我得到一个错误“没有用于文件扩展名“.vbs 测试”的引擎。

谁能建议我需要改变什么?

我在解决这个问题上取得了一些进展-

我把第一个脚本改成:

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

这样我就可以真正看到是否发生了什么事。

我把第二个脚本改成:

' 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 

并使用:wscript RunElevated.vbs OSVersion.vbs 测试

现在我在脚本运行时看到我在弹出窗口中回显的信息。

所以我回到问题 #1,我正在启动一个新的 shell 以在管理员模式下运行,所以如果我切换到 cscript 并尝试将信息写入标准输出或使用 Wscript.StdOut.Write,它将出现在新的外壳,我永远也看不到它,或者至少我认为问题是这样的。

有解决这个问题的标准方法吗?

【问题讨论】:

    标签: vbscript


    【解决方案1】:

    问题 #1:

    运行提升的脚本时看不到任何输出,因为 RunElevated.vbs 脚本使用 WScript.exe 重新启动 OSVersion.vbs 脚本。 OSVersion.vbs 使用只能从控制台获得的标准输入和输出。将 RunElevated.vbs 中的命令行更改为使用 cscript.exe 而不是 wscript.exe 可以解决此问题。更多内容请查看我的文章Error Trapping and Capturing Third-Party Output in WSH

    问题 #2

    您的问题似乎是您混合了不同类型的引号。命令应如下所示:

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

    试试这些脚本。

    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)
    

    为了捕获输出,我可能会尝试使用 WshShell Execute 方法的不同方法。有可用的命令行工具,例如ElevateHStart,可以使用提升的权限启动命令行。以下是我使用 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
    

    【讨论】:

    • 感谢 Nilpo,我所有的谷歌搜索都没有找到传递命令和参数的正确语法。我的最终目标是从 Java 运行 vbscript。 p = Runtime.getRuntime().exec(getVersion); InputStream s = p.getInputStream();这要求我从原始 shell 的标准输出中获取输出。你的文章看起来很不错。我需要尝试看看是否可以从原始外壳中的 ShellExecute 捕获标准输出。如果可以,那将解决我的最后一个问题。
    • 我读了你的文章。我是否正确,因为我使用的是 ShellExecute(因为我需要在提升模式下运行)并且 ShellExecute 创建了一个新窗口,所以运行 ShellExecute 的脚本无法从 ShellExecute 执行的脚本中检索标准输出?我能做的最好的事情就是创建一个文件并让原始脚本读取它?
    • 我在上面的答案中添加了更多内容。
    【解决方案2】:

    我发现了两件有趣的事情;首先,我必须得到正确数量的引号和空格,其次,我必须先调用一个临时脚本,然后调用提升的最终脚本。

    初始调用脚本 sn-p:

    If objFSO.FileExists("C:\Windows\System32\elevate.vbs") Then
         objWSHShell.ShellExecute "wscript.exe", Chr(34) & Chr(34) & "C:\Windows\System32\elevate.vbs" & Chr(32) & strCampus & Chr(32) & strLocation & Chr(32) & strAssetTag & Chr(34) & Chr(34), "", "", 1
    Else
         MsgBox "Regbrand script file not found",0,"Error Message"
    End If
    

    注意 Chr() 语句和 3 个变量从原始脚本传递到临时脚本。

    临时脚本sn-p:

    If Args.Count = 0 Then
        MsgBox "Missing arguments to UAC permissions script.",0,"Missing Parameters"
    Else
        strCampus = Args.Item(0)
        strLocation = Args.Item(1)
        strAssetTag = Args.Item(2)
    
        strFilePath = objFSO.GetParentFolderName (WScript.ScriptFullName)
        If objFSO.FileExists("C:\Windows\System32\regbrand.vbs") Then
             objWSHShell.ShellExecute "wscript.exe", Chr(34) & Chr(34) & "C:\Windows\System32\regbrand.vbs" & Chr(32) & strCampus & Chr(32) & strLocation & Chr(32) & strAssetTag & Chr(34) & Chr(34), "", "runas", 1
        Else
             MsgBox "Script file not found",0,"Error Message"
        End If
    End If
    

    在临时脚本中,我们将相同的参数传递给最终脚本。再次注意 Chr() 语句。

    第一个脚本传递 3 个参数并调用临时脚本,该脚本又以提升的权限调用第三个脚本“regbrand.vbs”。它就像它应该的那样工作。如果您删除临时脚本,它就不起作用。我还没有弄清楚,但相信这与从网络位置调用原始脚本有关。不过,我希望调用和传递参数的语法有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-09
      • 2016-07-02
      • 1970-01-01
      • 1970-01-01
      • 2015-01-05
      • 1970-01-01
      相关资源
      最近更新 更多