VBScript how to join WScript.Arguments? - windows-7

I am trying to join the arguments to a string to be passed to another script. The following:
WScript.Echo(Join(WScript.Arguments))
gives me an error:
Error: Wrong number of arguments or invalid property assignment
Code: 800A01C2
What is wrong with that syntax?

WshArgument objects are not arrays, so you can't use Join() on them. What you can do is something like this:
ReDim arr(WScript.Arguments.Count-1)
For i = 0 To WScript.Arguments.Count-1
arr(i) = WScript.Arguments(i)
Next
WScript.Echo Join(arr)

Another solution can be done with ArrayList object from the system:
Set oAL = CreateObject("System.Collections.ArrayList")
For Each oItem In Wscript.Arguments: oAL.Add oItem: Next
WScript.Echo Join(oAL.ToArray, " ")

ReDim arr(WScript.Arguments.Count-1)
For i = 0 To WScript.Arguments.Count-1
arr(i) = """"+WScript.Arguments(i)+""""
Next
WScript.Echo Join(arr)
this will add quotes for each argument,
you can then remove it in the batch file with %~1 and so on.

Here is the function that I use. It will return all the arguments whether they contain quotes or not in a string that you can pass to another script.
Function GetArguments()
Dim Args, Arg
If WSH.Arguments.Count > 0 Then
For Each Arg In WSH.Arguments
Args = Args & """" & Arg & """ "
Next
Args = " """"" & Trim(Args) & """"""
End If
GetArguments = Args
End Function

Related

Writing an output of shellExecute command with arguments into a log file in VBScript

I've tried a lot of things to accomplish this, but haven't succeeded yet in the way I'd like to.
I've got an hta app, that gathers parameters from checkboxes and then runs a cmd file passing those parameters there.
I want to create a log file of that process without creating any new wrapping files if a log checkbox is checked.
My logic is to run a script with arguments by another with redirecting parameter as an argument. And I can't get the syntax right (or is it even possible inside the same file). My simplified code:
Sub RunCmd
dim shell
dim shellWithLog
dim command
dim ARGS
set shell = createobject("Shell.Application")
set shellWithLog = createobject("wscript.shell")
command = "gui.cmd"
if (checkbox1.checked) then
ARGS = ARGS + " Do_This"
end if
if (checkbox2.checked) then
ARGS = ARGS + " Do_That"
end if
if (logFile.checked) then
shellWithLog.run (shell.shellExecute command, ARGS), " &>" + "publishLog.log", 1
else
shell.shellExecute command, , "runas", 1
end if
End Sub
This doesn't work, obviously, but at least shows what I'm trying to achieve.
To concatenate strings in VBScript, the & operator is used. The + operator is for numerical addition only.
Sub RunCmd
dim shell, ARGS
set shell = createobject("Shell.Application")
ARGS = ""
if checkbox1.checked then ARGS = ARGS & " Do_This"
if checkbox2.checked then ARGS = ARGS & " Do_That"
if logFile.checked then ARGS = ARGS & ARGS " > publishLog.log"
' ShellExecute(sFile, [vArgs], [vDirectory], [vOperation], [vShow])
' https://msdn.microsoft.com/en-us/library/windows/desktop/gg537745(v=vs.85).aspx
shell.shellExecute "gui.cmd", ARGS, , "runas", 1
End Sub

Vbscript Function Print Output

I have create VBscript to enumerate user in group
Function GetUserInGroup()
strComputer = "localhost"
Set colGroups = GetObject("WinNT://" & strComputer & "")
colGroups.Filter = Array("group")
For Each objGroup In colGroups
For Each objUser in objGroup.Members
If objUser.name = "yayantritaryana" Then
WScript.stdout.write objGroup.Name + " "
End If
Next
Next
End Function
WScript.stdout.write "Group=" + GetUserInGroup
But when i execute it, the output is'nt what i expected
The output I Wanted is like
Group=Administrator SQLAdmin Sysadmin
Can someone help me ?
A Function has a purpose (eg. delivering a string of space separated group names). For that you assign the desired result to the function's name (other languages use some kind of return statement):
Function GetUserInGroup()
GetUserInGroup = "pi pa po"
End Function
WScript.stdout.write "Group=" & GetUserInGroup()
output:
cscript 29053176.vbs
Group=pi pa po
A function shouldn't have side-effects (like your
WScript.stdout.write objGroup.Name + " "
which prints names to the console before you output "Group=" in the last line of your script). Instead concatenate the objGroup.Names.
The operator for string concatenation is &.
The (possibly empty) argument list of a function call must be enclosed by (); these param list () are illegal for Sub calls.
Some extra code as food for thought:
Function GetUserInGroup()
For Each s In Split("pi pa po")
GetUserInGroup = GetUserInGroup & s & "*"
' GetUserInGroup = GetUserInGroup() & s & "*"
Next
End Function
WScript.stdout.write "Group=" & GetUserInGroup()

Vbscript start vbs with arguments and define multiple arguments

I need to start a vbs script by an argument and related to the passed argument see a pop up.
Example :
Dim Arg, var1, var2
Set Arg = WScript.Arguments
'Parameter1, begin with index0
var1 = Arg(0)
if (instr(WScript.Arguments.Name,"Printer")> 0 then
wscript.echo "Printer type..."
end if
if (instr(WScript.Arguments.Name,"help")> 0 then
wscript.echo "help..."
end if
Thanks in advance
'Clear the objects at the end of your script.
set Arg = Nothing
call you script like so
myscript.vbs /help
and access args like so
'setup the named argument collection
set argNamedCollection = WScript.Arguments.Named
'get the arguments passed in
argHelp = argNamedCollection.Item("help")
argPrinter = argNamedCollection.Item("printer")
'or check directly
'check for help arguments
if argNamedCollection.Exists("help") then
'do somthing
end if

Force a VBS to run using cscript instead of wscript

What is the stackoverflow approved (and hence correct) method to force a VBS to run using cscript instead of wscript - irrespective of what the user tries?
A quick Google search shows plenty of examples, but some of them simply don't work and those which do often don't handle the fact that it may have been run with arguments so I'm keen to know what the best way is.
Here is one example which doesn't handle arguments:
sExecutable = LCase(Mid(Wscript.FullName, InstrRev(Wscript.FullName,"\")+1))
If sExecutable <> "cscript.exe" Then
Set oShell = CreateObject("wscript.shell")
oShell.Run "cscript.exe """ & Wscript.ScriptFullName & """"
Wscript.Quit
End If
I appreciate that this could probably be easily modified to handle arguments, but realise that this may not be the best way to approach the problem.
Background: I'm writing a script which can run by double clicking or (most likely) from either a DOS batch file or as a scheduled task. It can contain one or more optional command line arguments.
My Lord, what unadulterated rubbish. It makes me cry to see such cruddy coding (no offense to anybody, lol). Seriously, though, here's my 2 pence:
Sub forceCScriptExecution
Dim Arg, Str
If Not LCase( Right( WScript.FullName, 12 ) ) = "\cscript.exe" Then
For Each Arg In WScript.Arguments
If InStr( Arg, " " ) Then Arg = """" & Arg & """"
Str = Str & " " & Arg
Next
CreateObject( "WScript.Shell" ).Run _
"cscript //nologo """ & _
WScript.ScriptFullName & _
""" " & Str
WScript.Quit
End If
End Sub
forceCScriptExecution
It handles arguments, AND checks for spaces in said arguments -- so that in the case of a filename passed to the original script instance that contained spaces, it wouldn't get "tokenized" when passed to cscript.exe.
Only thing it doesn't do is test for StdIn (e.g., in the case where someone piped something to the script via the command line, but forgot to use "cscript script.vbs") -- but if it was executed by WScript.exe, WScript.StdIn's methods all return Invalid Handle errors, so there's no way to test that anyway.
Feel free to let me know if there's a way to "break" this; I'm willing to improve it if necessary.
Two small additions to forceCScriptExecution let me see its Window after termination and handle its return code.
Sub forceCScriptExecution
Dim Arg, Str
If Not LCase( Right( WScript.FullName, 12 ) ) = "\cscript.exe" Then
For Each Arg In WScript.Arguments
If InStr( Arg, " " ) Then Arg = """" & Arg & """"
Str = Str & " " & Arg
Next
**ret =** CreateObject( "WScript.Shell" ).Run **("cmd /k** cscript //nologo """ & WScript.ScriptFullName & """ " & Str**,1,true)**
WScript.Quit **ret**
End If
End Sub
Notes: "cmd /k" let the windows stay after execution. Parameter "1" activates the window. Parameter "true" waits for termination, so variable "ret" can return the error code.
Here's a similar one in JScript for making .js files run in CScript:
(function(ws) {
if (ws.fullName.slice(-12).toLowerCase() !== '\\cscript.exe') {
var cmd = 'cscript.exe //nologo "' + ws.scriptFullName + '"';
var args = ws.arguments;
for (var i = 0, len = args.length; i < len; i++) {
var arg = args(i);
cmd += ' ' + (~arg.indexOf(' ') ? '"' + arg + '"' : arg);
}
new ActiveXObject('WScript.Shell').run(cmd);
ws.quit();
}
})(WScript);
WScript.echo('We are now in CScript. Press Enter to Quit...');
WScript.stdIn.readLine();
https://gist.github.com/4482361
One approach might be to give it another extension instead of .vbs. Say .cvbs for example. Associate .cvbs with cscript.exe not wscript.exe, that way executing or double clicking a .cvbs file will never invoke the wscript.exe.
Here is my code snippet i use for some of my scripts. It handles Arguments as well. All you have to do is replace the {EnterWorC} with either a "w" or "c" WITH quotes
Dim WorC, Command, Arguments, I
WorC={EnterWOrC} 'Make sure you replace "{EnterWOrC}" with a "w" or a "c" and BE SURE TO PUT QUOTES AROUND THE LETTER.
WorC=LCase (WorC)
If lcase (WorC)="w" Or lcase (WorC)="c" Then
If LCase (Right (WScript.FullName,11))<> WorC & "script.exe" Then
command=WScript.ScriptFullName
Arguments=""
For I=0 To UBound (WScript.Arguments)
Arguments=Arguments & Chr (34) & WScript.Arguments(I) & Chr (34) & Space (1)
Next
CreateObject("Wscript.Shell").Run WorC & "script.exe " & Chr (34) & command & Chr (34) & Space (1) & Arguments, 1
WScript.Quit
End If
WorC=Empty
Command=Empty
I=Empty
Arguments=Empty
End If
Here you will have to replace the 2nd line (2nd NON-blank line)
WorC={EnterWOrC} 'Make sure you replace "{EnterWOrC}" with a "w" or a "c" and BE SURE TO PUT QUOTES AROUND THE LETTER.
For Wscript: WorC="W"
For CScript: WorC="C"
It is NOT case Sensitive.

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