Jan 26

Running VBScripts with UAC Elevation

Overview

Since the introduction of User Account Control (UAC), scripts do not run with administrator privileges despite being a local administrator.  You must elevate your script to run with administrator privileges. I’ll start by showing you a simple example.  The script below will list all of the processes on the local computer as well as the WIN32_Process CommandLine property.  If you run the script on a computer with UAC without elevating it, you will only see CommandLine values for processes created by your account; if any other processes were created by another account, the CommandLine property will be NULL.

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Process",,48)
For Each objItem in colItems
Wscript.Echo "Process: " & objItem.Name & vbCrLf & _
"Startup: " & objItem.CommandLine
Next

 

On a test machine, I was logged on as User1, opened notepad, and launched a vbscript as the local administrator account using RunAs.  I ran the script above and compared the results to task manager with the following results:

As you can see, the script successfully showed the CommandLine property for the currently logged on user

User1 Test Script Notepad Process Results

User1 Task Manager Notepad Process Results

However, the test script failed to show the CommandLine property for the wscript.exe process running as administrator:

Administrator Test Script Wscript Process Results

Administrator Task Manager Wscript Process Results

By re-running the test script with elevated privileges, the script now successfully shows the CommandLine property for the wscript process running as Administrator.

Administrator Elevated Test Script Wscript Process Results

Now that I have successfully demonstrated the need to run a script elevated on a local machine, you might be wondering what happens when you the test script on a remote machine.  If you run the script on a remote machine that you have administrator rights on, it will successfully display the CommandLine property for all users.  Now, you might be confused as to why it works remotely?  The answer is quite simple, the script is elevated by RPC.  Now that you have a good understanding of running vbscripts with UAC elevation, here are some methods on how to elevate them.

 

 Method 1 – Elevating Using the Command Prompt

  1. Click Start, All Programs, Click Accessories
  2. Right-click Command Prompt and click Run as administratorRun Elevated Command Prompt
  3. Click Yes
    1. CMD UAC Prompt
  4. Any script you launch using wscript.exe or cscript.exe will launch elevated

Method 2 – RunAs Script

This method uses a wrapper script to run an elevated VBScript using the runas verb with the ShellExecute method of Shell.Application.  When it launches the elevated script, click Yes

http://sigkillit.com/2013/01/25/elevatewscript-vbs/

VBS UAC Prompt

 

Method 3 – Add ‘Run as administrator’ to the .vbs File Context Menu

The ‘Run as administrator’ option on a File Context Menu is only available on certain file types by default, and .vbs files are not one of them.  However, by doing a quick registry modification we can enable the ‘Run as administrator’ option o the file context menu.  Download and run the following registry to merge it into your registry, or you can copy the below text and save it to a .reg file:

Add Run as administrator to VBS File Context Menu

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\VBSFile\Shell\runas]
"HasLUAShield"=""

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\VBSFile\Shell\runas\Command]
@=hex(2):22,00,25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,\
00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,57,00,\
53,00,63,00,72,00,69,00,70,00,74,00,2e,00,65,00,78,00,65,00,22,00,20,00,22,\
00,25,00,31,00,22,00,20,00,25,00,2a,00,00,00

 

Jan 25

ElevateWscript.vbs

'=========================================================================
' ElevateWscript.vbs
' VERSION: 1.0
' AUTHOR: Brian Steinmeyer
' EMAIL: sigkill@sigkillit.com
' WEB: http://sigkillit.com
' DATE: 1/25/2012
' COMPATIBLE: Windows Vista, Server 2008, and Above
' COMMENTS: Since the introduction of UAC in Windows, despite being an
' administrator you may still need to run a script with elevated
' privileges. For example the CommandLine property of the WIN32_Process class
' requires a script to be elevated in order to return valid data when the process
' is running as another user. Unfortunately, Windows does not provide Run As
' Administrator on the context of a .vbs file, which is why I made this.
' To use the script, pass the full path to a .vbs file to the Sub and it
' will prompt you to run the script elevated. If the script you need to elevate
' in located in the same directory as this script, you can just pass the script
' name. Alternatively, you can always launch your vbscript from an elevated
' command prompt which will use wscript or cscript elevated as well.
' EXAMPLE: Elevate a script using the full path
'          Call ElevateWscript("C:\scripts\test.vbs")
' EXAMPLE: Elevate a script in the same directory as ElevateWscript.vbs
'          Call ElevateWscript("test.vbs")
'=========================================================================
Option Explicit
Call ElevateWscript("test.vbs")

Private Sub ElevateWscript(scriptName)
    Dim objShell: Set objShell = CreateObject("Shell.Application")
    Dim objFSO: Set objFSO = CreateObject("Scripting.FileSystemObject")
    If objFSO.FileExists(scriptName) Then
        Dim objFile: Set objFile = objFSO.GetFile(scriptName)
         objShell.ShellExecute "wscript.exe", Chr(34) & objFile.Path & Chr(34), "", "runas", 1
    Else
         Wscript.Echo "Script Does Not Exist!" & vbCrLf & scriptName
    End If
End Sub

 

Dec 21

ListRunningScripts.vbs

'=========================================================================
' ListRunningScripts.vbs
' VERSION: 1.1 - Null value is returned when a script is launched by another user on the local computer and the script is not elevated for UAC. I added a check to look for this and alert the user.
' AUTHOR: Brian Steinmeyer
' EMAIL: sigkill@sigkillit.com
' WEB: http://sigkillit.com
' DATE: 12/21/2012
' COMPATIBLE: Windows XP, Server 2003, and Above
' COMMENTS: If you ever had a wscript.exe or cscript.exe process running but
' need to know the exact script it is running you can find the answer using
' the CommandLine property in the WIN32_Process Class. You can view this
' property in Task Manager by clicking View->Choose Columns. Alternatively,
' you can script it as I have below. The script works on the local computer
' as well as remote computers. Set the computer to run the script against
' and optionally set it to show the Scripting Host that launched the script.
' EXAMPLE: List Running Scripts on Local Computer Without Script Host
'          Dim strComputer: strComputer = "."
'          Dim blnShowScriptHost: blnShowScriptHost = False
' EXAMPLE: List Running Scripts on Local Computer With Script Host
'          Dim strComputer: strComputer = "."
'          Dim blnShowScriptHost: blnShowScriptHost = True
' EXAMPLE: List Running Scripts on Remote Computer Without Script Host
'          Dim strComputer: strComputer = "server"
'          Dim blnShowScriptHost: blnShowScriptHost = False
' EXAMPLE: List Running Scripts on Remote Computer With Script Host
'          Dim strComputer: strComputer = "server"
'          Dim blnShowScriptHost: blnShowScriptHost = True
'=========================================================================
Option Explicit
' ------ SCRIPT CONFIGURATION ------
Dim strComputer: strComputer = "."
Dim blnShowScriptHost: blnShowScriptHost = False
' ------ END CONFIGURATION ------

Wscript.Echo ListRunningScripts(strComputer)

Private Function ListRunningScripts(strComputer)

    On Error Resume Next

    Dim objWMIService: Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Dim colProcesses: Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = " & "'Wscript.exe' OR Name = 'Cscript.exe'")
    Dim objProcess
    Dim strResult: strResult = ""
    Dim count: count = 0
    If Not colProcesses.Count = 0 Then
        For Each objProcess in colProcesses
            count = count + 1
            If blnShowScriptHost = True Then
                strResult = strResult & objProcess.CommandLine & vbCrLf
            Else
                If IsNull(objProcess.CommandLine) OR IsNull(objProcess.ExecutablePath) Then
                    strResult = strResult & "NULL (You need to use Run As Administrator)" & vbCrLf
                Else
                    strResult = strResult & Trim(Replace(Replace(objProcess.CommandLine, objProcess.ExecutablePath, "", 1, 1, 1), objProcess.Name, 1, 1, 1)) & vbCrLf
                End If
            End If
        Next
    End If

    strResult = count & " Scripts are running" & vbCrLf & "----------------------" & vbCrLf & strResult

    If Err.Number <> 0 Then
        Err.Clear
        strResult = "!~ERROR~!"
    End If

    ListRunningScripts = strResult

    On Error Goto 0

End Function

 

Dec 08

IDK.vbs

'=========================================================================
' IDK.vbs
' VERSION: 1.0
' AUTHOR: Brian Steinmeyer
' EMAIL: sigkill@sigkillit.com
' WEB: http://sigkillit.com
' DATE: 12/8/2012
' COMMENTS: If you have ever had an issue making a decision like "What Should
' I eat for dinner" or "What should I do tonight?" then IDK aka "I Don't Know"
' is the script for you. It will randomly select a decision for you from a line
' delimited text file you pass to the script. You can run the script with Wscript
' by dragging and dropping your file onto the script or with Cscript by using
' the file path as the argument passed. You can make lists for all types of
' decisions you commonly make, and a few ideas are Yes/No, Magic8Ball, Pizza Shops,
' Restaurants, Movies, etc.
' EXAMPLE: Drag-N-Drop with WScript
'          Drag and Drop a file called Pizza.txt onto IDK.vbs to select a pizza shop
' EXAMPLE: From and command prompt with Cscript
'          C:\>cscript IDK.vbs "C:\My Lists\pizza.txt"
'=========================================================================
Option Explicit

Wscript.Echo IDK(wscript.arguments.item(0))

Private Function IDK(filePath)

    On Error Resume Next

    Const ForReading = 1
    Dim strResult
    Dim objFSO: Set objFSO = CreateObject("Scripting.FileSystemObject")
    If Not objFSO.FileExists(filePath) Then
        strResult = "ERROR - Input File Does Not Exist!"
    Else
        'Parse Input File into Array
        Dim objTextFile: Set objTextFile = objFSO.OpenTextFile(filePath, ForReading)
        Dim arrLine()
        Dim intSize: intSize = 0
        Dim strLine, blnMatch: blnMatch = False
        Do Until objTextFile.AtEndOfStream
            strLine = Trim(objTextFile.Readline)
            If Not strLine = "" Then
                blnMatch = True
                ReDim Preserve arrLine(intSize)
                arrLine(intSize) = strLine
                intSize = intSize + 1
            End If
        Loop
        'Randomly Select
        Dim intHighNumber: intHighNumber = UBound(arrLine)
        Dim intLowNumber: intLowNumber = LBound(arrLine)
        Dim intNumber
        Randomize
        strResult = arrLine(Int((intHighNumber - intLowNumber + 1) * Rnd + intLowNumber))      
    End If

    'Return Results
    If Err.Number <> 0 Then
        Err.Clear
        strResult = "ERROR - Parsing Input File!"
    End If 
    IDK = strResult

    Set objFSO = Nothing

    On Error Goto 0

End Function

 

Apr 01

EmailParts.vbs

'=========================================================================
' EmailParts.vbs
' VERSION: 1.0
' AUTHOR: Brian Steinmeyer
' EMAIL: sigkill@sigkillit.com
' WEB: http://sigkillit.com
' DATE: 4/1/2012
' COMMENTS: Four methods to break an email address into the local and
' domain parts. I prefer the string methods because you can make them
' 1-liners, doesn't require additional variables, and simplifies error
' handling.  
'=========================================================================
Option Explicit

Call EmailParts1("john.doe@domain.com")
Call EmailParts2("john.doe@domain.com")
Call EmailParts3("john.doe@domain.com")
Call EmailParts4("john.doe@domain.com")

'METHOD1(String) - Left/Right with Instr
Sub EmailParts1(email)
    Wscript.Echo "METHOD 1:" &amp; vbCrLf &amp; _
    "Email: " &amp; email &amp; vbCrLf &amp; _
    "Local: " &amp; Left(email,InStr(1,email,"@",1)-1) &amp; vbCrLf &amp; _
    "Domain: " &amp; Right(email,(Len(email)-InStr(1,email,"@",1))+1)  
End Sub

'METHOD2(String) - Left/Right with InstrRev
Sub EmailParts2(email)
    Wscript.Echo "METHOD 2:" &amp; vbCrLf &amp; _
    "Email: " &amp; email &amp; vbCrLf &amp; _
    "Local: " &amp; Left(email,InstrRev(email,"@")-1) &amp; vbCrLf &amp; _
    "Domain: " &amp; Right(email,(Len(email)-Instr(email,"@"))+1)
End Sub

'METHOD3(String) - Mid with InStr
Sub EmailParts3(email)
    Wscript.Echo "METHOD 3:" &amp; vbCrLf &amp; _
    "Email: " &amp; email &amp; vbCrLf &amp; _
    "Local: " &amp; Mid(email, 1, InStr(email, "@")-1) &amp; vbCrLf &amp; _
    "Domain: " &amp; Mid(email,InStr(email,"@"),Len(email)-(InStr(email,"@")-1))
End Sub

'METHOD4(Array) - Split dumps into an array (NOT RECOMMENDED)
Sub EmailParts4(email)
    Dim arrEmail: arrEmail = Split(email,"@")
    arrEmail(1) = "@" &amp; arrEmail(1) 'Need to add @ back in
    Wscript.Echo "METHOD 4:" &amp; vbCrLf &amp; _
    "Email: " &amp; email &amp; vbCrLf &amp; _
    "Local: " &amp; arrEmail(0) &amp; vbCrLf &amp; _
    "Domain: " &amp; arrEmail(1)
End Sub

 

Jan 01

ScriptSuicide.vbs

'=========================================================================
' ScriptSuicide.vbs
' VERSION: 1.0
' AUTHOR: Brian Steinmeyer
' EMAIL: sigkill@sigkillit.com
' WEB: http://sigkillit.com
' DATE: 1/1/2011
' COMMENTS: Deletes the current script. This is useful when you are running
' scripts to automate tasks such as installations, logins, etc and you want
' to remove the script after it executes.
' EXAMPLE: Call ScriptSuicde()
'=========================================================================
Option Explicit

Call ScriptSuicide()

Private Sub ScriptSuicide()

    On Error Resume Next

    Dim objFSO: Set objFSO = CreateObject("Scripting.FileSystemObject")
    objFSO.DeleteFile WScript.ScriptFullName
    Set objFSO = nothing

    On Error GoTo 0

End Sub