Quoting in VBscript - vbscript

I am using vbscript to query an "at" job that is executing a specific command and I believe I have the quoting wrong. I have confirmed the script works as intended when I query something that does not contain spaces or quotes; however when I query for something that contains spaces and quotes I do not get the desired results. The exact value I want to find is:
cmd /c "C:\Test Folder\Folder1\Blah.cmd"
Here is the code I am using:
strComputer = "."
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\"_
& strComputer & "\root\cimv2")
Set colRandJob = objWMIService.ExecQuery _
("Select * from Win32_ScheduledJob WHERE Command='cmd /c ""C:\Test Folder\Folder1\Blah.cmd""' ")
For Each objJob in colRandJob
WScript.Echo "Found AT Job with ID " + CStr(objJob.JobID)
Next
I have tried a few different things and cant seem to find the right way. Can someone help me out and let me know the proper way to do this?
Update
I was able to resolve the issue by doing the following (I am only including the relevant lines) I have not tested this without the double back slash's in the path, but I believe it is required along with the new quoting I have used:
'Assign the string I'm looking for to a variable
set targetCmd = "cmd /c "C:\\Test Folder\\Folder1\\Blah.cmd""
Set colRandJob = objWMIService.ExecQuery _
("Select * from Win32_ScheduledJob WHERE Command='" & targetCmd & "' ")

Backslash (\) is an escape character in WMI. So, WMI queries must use double backslashes \\ in place of each single backslash:
Set colRandJob = objWMIService.ExecQuery _
("Select * from Win32_ScheduledJob WHERE Command='cmd /c ""C:\\Test Folder\\Folder1\\Blah.cmd""' ")

Use """" to produce a string containing only " and also use & to concatenate your string first.
mystring = "cmd /c " & """"C:\Test Folder\Folder1\Blah.cmd"""
(not tested )

Related

Use VBS to run a program with parameters

I'm a total vbs novice trying to perform the supposedly simple task of using a vbscript to run a single program (with parameters).
The path the to program is:
C:\Program Files (x86)\SpeedyFox\speedyfox.exe
and the parameter switch that must go with it is:
/Firefox:C:\Program Files\Firefox\Data\profile
If I wrap both sections in quotes (due to the spaces in their paths) it gives the following combined single command:
"C:\Program Files (x86)\SpeedyFox\speedyfox.exe" "/Firefox:C:\Program Files\Firefox\Data\profile"
If I then paste this into Start > Run it works exactly as I want.
I'm just trying to achieve the same thing from a vbs script instead of manually pasting into the Run box.
I do not want the command to run within a CMD console (as other questions on here have asked). All I am trying to do is to get "C:\Program Files (x86)\SpeedyFox\speedyfox.exe" "/Firefox:C:\Program Files\Firefox\Data\profile" to work with the shell.ShellExecute line of the script below.
Set objShell = Wscript.CreateObject ("Wscript.shell")
set shell=CreateObject("Shell.Application")
shell.ShellExecute ** WHAT DO I PUT HERE? **
set shell=nothing
but try as I might, I just keep getting WSH "Expected end of statement" error messages.
1.First : I recommend you Make it a habit to use this quote function
to make it easy for you to quote variables in these situations !
2. Second : You should use MsgBox or Wscript.echo in order to show
and debug your variables easily !
Wscript.echo DblQuote("Hello World !")
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
So, I downloaded this application (speedyfox.exe) and i tested it on my Windows 10 (32bits)
So, here is what i tested and it works like a charm on my side :
Option Explicit
Dim objShell,MyCommand,strProgramFiles,SpeedyFoxfile,Title
Title = "Execute SpeedyFox in Commandline"
Set objShell = CreateObject("Shell.Application")
strProgramFiles = GetProgramFilesPath()
SpeedyFoxfile = strProgramFiles & "\SpeedyFox\speedyfox.exe"
MsgBox "Without Double Quotes" & vbCrlf & SpeedyFoxfile,vbInformation,Title
MsgBox "With Double Quotes" & vbCrlf & DblQuote(SpeedyFoxfile),vbInformation,Title
MyCommand = "CD /D "& DblQuote(strProgramFiles &"\SpeedyFox\") &"&"& DblQuote(SpeedyFoxfile) & " " & DblQuote("/Firefox:default") & " " & DblQuote("/Chrome:Default")
MsgBox MyCommand,vbInformation,Title
Call Execute(MyCommand)
'-----------------------------------------
Function Execute(StrCmd)
Dim ws,MyCmd,Result
Set ws = CreateObject("wscript.Shell")
MyCmd = "CMD /K " & StrCmd & ""'
Result = ws.run(MyCmd,1,True)
Execute = Result
End Function
'-----------------------------------------
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'-----------------------------------------
Function GetProgramFilesPath()
Dim ws,OsType,strProgramFiles
Set ws = createObject("WScript.Shell")
OsType = ws.RegRead("HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\PROCESSOR_ARCHITECTURE")
If OsType = "x86" then
strProgramFiles = ws.ExpandEnvironmentStrings("%PROGRAMFILES%")
elseif OsType = "AMD64" then
strProgramFiles = ws.ExpandEnvironmentStrings("%PROGRAMFILES(x86)%")
end if
GetProgramFilesPath = strProgramFiles
End Function
'-----------------------------------------
Sigh, reminds me of my vbscript days, now I use Ruby and it's just as simple as
´my_shell_command params´
However, back to your question: the shortest way to use ShellExecute is
CreateObject("Shell.Application").ShellExecute "application", "parameters", "dir", "verb", window
See this documentation for explanation of the parameters.
EDIT:
You have to pay attention at the quotes, they need to be passed to the shell also by using two quotes
eg CreateObject("Shell.Application").ShellExecute "C:\Program Files (x86)\SpeedyFox\speedyfox.exe", """/Waterfox:C:\Program Files\Waterfox\Data\profile"""

WshShell.Run of executable from UserProfile variable directory

I thought I had this correct but I don't. I'm trying to have an executable called from user profile directory. The variable is not expanding properly. This is the code example:
userProfilePath = oShell.ExpandEnvironmentStrings("%UserProfile%")
exePath = userProfilePath + "\test1.exe"
Set WshShell = WScript.CreateObject(""WScript.Shell"")
WshShell.Run """ & exePath & """
When the VBScript runs, it doesn't properly show the path of ("C:\Users\John Doe\test1.exe"). What am I missing on how to use the variable and string correctly?
Your quoting is incorrect. WScript.Shell must be in a single pair of double quotes, and if you want to add double quotes before and after the value of a variable you need to use either Chr(34)
WshShell.Run Chr(34) & exePath & Chr(34)
or sequences of 4 double quotes:
WshShell.Run """" & exePath & """"
The reason for the 4 consecutive double quotes is that VBScript string literals must begin and end with a double quote, and nested double quotes inside a string literal must be escaped by doubling them (so they don't prematurely terminate the string). Your literal """ & exePath & """ defines the literal text " & exePath & ", not the value of the variable exePath between two double qoutes.
With that said, in your particular case you don't need the whole concatenation shebang, because the Run method can handle environment variables by itself. The following code should suffice for your needs:
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run """%USERPROFILE%\test1.exe"""

Comparing WMI DateTime to String in Query

I'm trying to query Win32_NTLogEvent for entries past the previous time that I ran the query. I've tried using a string variable so that I can change it every time I run the script. But I am getting a null returned for the generated collection. I've looked up what I can about WMI DateTimes and using them in comparisons. Although I have found some seemingly conflicting information (namely some sources using human readable to compare directly with UTC and others not). I've tried a UTC string and a human readable string. But neither seem to work. I'm thinking it is because I need to compare a datetime to a datetime as opposed to a string to a string. Although many sources seem to say that a string to a string would work in this case. But, even if I am right, I'm not sure how to convert the time for every object in Win32_NTLogEvent while inside the query.
Here is the relevant part of my script. The UTC that is commented out is just there because I don't want to retype the date if I have to go back to UTC:
strTimeMin = "01/01/1970/0:00:00"
'19700101000000.000000-480
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'Querying Event Logs
Set colLoggedEvents = objWMIService.ExecQuery _
("SELECT * FROM Win32_NTLogEvent WHERE Logfile = 'system' AND "_
& "Type = 'Error' AND TimeGenerated > " & strTimeMin & "")
Thanks for any help!
UTC strings should work fine. However, since they're strings you need to put them between single quotes in your WMI query:
computer = "..."
minTime = "20140801000000.000000-000"
Set wmi = GetObject("winmgmts:\\" & computer & "\root\cimv2")
qry = "SELECT * FROM Win32_NTLogEvent " & _
"WHERE LogFile = 'System' AND Type = 'Error' " & _
"AND TimeGenerated > '" & minTime & "'"
For Each evt In wmi.ExecQuery(qry)
...
Next

Passing value with spaces as cmd parameter to programs

strTarget = "C:\My Name\K.jpg"
as you can see there is a space in the address which is stored in strTarget, Now I\m trying to pass it to an application, but it won't work because there is space in address :(
TargetApp.Run """C:\My App\here.exe"" " & strTarget ,,true
if I change strTarget into "C:\MyName\K.jpg" which does not have space it will work.
How to solve this problem?
You need to add double quotes around the image path the same way you did around the executable path:
TargetApp.Run """C:\My App\here.exe"" """ & strTarget & """" ,,true
I usually recommend using a quoting function for this, because it significantly increases the readability:
Function qq(str) : qq = Chr(34) & str & Chr(34) : End Function
app = "C:\My App\here.exe"
img = "C:\My Name\K.jpg"
TargetApp.Run qq(app) & " " & qq(img), 0, True

Double quotes in VBScript argument

As I read and experienced for myself VBScript removes all double quotes from and argument. Does anyone know a way around this? How to pass double quotes into the script?
If that parameter requires quotes you could use a named parameter to identify it and then enclose the value with the double quotes
dim arg
if WScript.Arguments.Named.Exists("a") then
arg = WScript.Arguments.Named("a")
arg = chr(34) & arg & chr(34)
end if
and used thus:
cscript test.vbs /a:"a parameter"
but this doesn't help if you merely want to keep quotes if supplied. Single quotes are accepted though, so you could alternatively use single quotes (or another character/string) and do a Replace(arg, "'", chr(34)) to convert to double-quotes.
This script will get the command line as it is, with double quotes and everything to a variable called strLine, and display it:
Set objSWbemServices = GetObject("WinMgmts:Root\Cimv2")
Set colProcess = objSWbemServices.ExecQuery("Select * From Win32_Process")
For Each objProcess In colProcess
If InStr (objProcess.CommandLine, WScript.ScriptName) <> 0 Then
strLine = Mid(objProcess.CommandLine, InStr(objProcess.CommandLine , WScript.ScriptName) + Len(WScript.ScriptName) + 1)
End If
Next
WScript.Echo(strLine)
So running that with:
cscript scriptname.vbs "option" ""other option"" third option
would result in:
"option" ""other option"" third option
Rather than check for a command line to include WScript.ScriptName, you can get the current PID like in https://stackoverflow.com/a/13212628/1752986
Edit: Misunderstood the question so new answer here:
I don't think you can do that in any way. However, a work around might be to use the CommandLine property of the Win32_Process class, which should get you the complete commandline I think.
For example try this script:
Set wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set processes = wmi.ExecQuery("SELECT * FROM Win32_Process")
For Each proc in processes
If InStr(proc.CommandLine, "double quotes") > 0 Then
wscript.echo proc.CommandLine
End IF
Next
With the parameters as: "some long commandline enclosed in double quotes here"
I am not sure if this works, but while passing parameter I guess you can do something like -
chr(34) + <your argument string> + chr(34)
The chr(34) stands for double quotes.
Unfortunately, I do not know any escape methods to pass double-quotes because its an argument delimiter. All I can suggest is to modify your script, or add the quotes from there.
Here's answer that draws upon/combines some of the others here and queries the process info based on the script's pid:
Function ArgumentsString()
Dim nPid : nPid = ThisProcessId()
For Each oPrc In GetObject("winmgmts:\\.\root\cimv2").ExecQuery(_
"Select * From Win32_Process Where ProcessId=" & nPid )
Exit For : Next
ArgumentsString = Mid( oPrc.CommandLine, _
InStr(oPrc.CommandLine, WScript.ScriptName) + _
Len(WScript.ScriptName) + 1 )
End Function
Function ThisProcessId()
ThisProcessId = 0
Dim sTFile, oPrc
With CreateObject("Scripting.FileSystemObject")
sTFile = .BuildPath(.GetSpecialFolder(2), "sleep.vbs")
With .OpenTextFile(sTFile, 2, True)
.Write "WScript.Sleep 1000"
End With
End With
With CreateObject("WScript.Shell").Exec("WScript " & sTFile)
For Each oPrc In GetObject("winmgmts:\\.\root\cimv2").ExecQuery(_
"Select * From Win32_Process Where ProcessId=" & .ProcessID)
Exit For : Next
ThisProcessId = oPrc.ParentProcessId
End With
End Function

Resources