How to call Run() with parameters - batch-file

I've got this working line of code in Windows Batch
start "" /wait /i "C:\Program Files\Sandboxie\Start.exe" /box:NetBeans /wait "C:\Program Files\NetBeans 7.3\bin\netbeans64.exe"
I would like to run it via VBScript. But I don't know how to pass the path in parameter which has a space inside.
I came up with something like this:
Set objShell = CreateObject("Wscript.Shell")
objShell.Run("C:\Program Files\Sandboxie\Start.exe" /box:NetBeans /wait "C:\Program Files\NetBeans 7.3\bin\netbeans64.exe"), 1, True
But there is an error:
expected: ')'

Within a literal string, a single double-quote character is represented by two double-quote characters. So try the following instead:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run """C:\Program Files\Sandboxie\Start.exe"" /box:NetBeans /wait ""C:\Program Files\NetBeans 7.3\bin\netbeans64.exe""", 1, True
Set objShell = Nothing

I like to use the following system to embed quotes :
strCommand = Quotes("C:\Program Files\Sandboxie\Start.exe") & _
" /box:NetBeans /wait " & _
Quotes("C:\Program Files\NetBeans 7.3\bin\netbeans64.exe")
Function Quotes(ByVal strValue)
Quotes = Chr(34) & strValue & Chr(34)
End Function
It's a lot easier to read.

Related

VBS running a file on a .bat

I am trying to run a .bat file as part of my VBScript with the parameter of another file.
I have tried:
param1 = CurrentFolder & "\file.extension"
command = "C:\folder name\compiler.bat"
Set WScript = CreateObject("WScript.Shell")
WScript.run "cmd " & command & " " & param1
But nothing seems to work.
Im trying to achieve the same as if I dragged "file.extension" and dropped it onto "compiler.bat"
Choose a different name for your Shell object. WScript is a built-in, global object in WSH. For example:
Set objShell = CreateObject("WScript.Shell")
Try this for your Run statement:
objShell.Run "cmd /c " & Chr(34) & Chr(34) & command & Chr(34) & " " & Chr(34) & param1 & Chr(34) & Chr(34)
The /c will close the prompt when the command completes. The Chr(34)'s are used to put quotes around your command and your parameter, in case either contains spaces. Note that you also need quotes around the entire statement. For example:
cmd /c ""c:\folder name\compiler.bat" "a param with spaces""

.vbs(5, 1) Microsoft VBScript runtime error: Subscript out of range Error:800A0009

This is my first question on here, because, although I have searched at least 15 different other posts for the answer to my issue, none have the answer. Please help!
QUESTION: How do I fix Error:800A0009?
DETAILS: I am creating a small program that gathers all local computers and sends them all an audio file to be played. Also, I need to know how to force send, if anyone knows. Lastly, I first run "Get Computers.bat".
My Code:
~~~~~~VBS FILE(Remote Speak.vbs)~~~~~~~~~~~~~~~~~~~
(Obtains variable transferred which contains network name of a computer, and sends it a file to be play using SAPI)
'get ip
Option Explicit
Dim args, strOut
set args = Wscript.arguments
strOut= args(0)
IP = strOut
'get MSG
MSG = InputBox("Type what you want the PC to say:", "Remote Voice Send By X BiLe", "")
If MSG = "" Then WScript.quit: Else
'vbs command to send
A = "on error resume next" & VBCRLF & _
"CreateObject(""SAPI.SpVoice"").speak " & """" & MSG & """" & VBCRLF & _
"CreateObject(""Scripting.FileSystemObject"").DeleteFile (""C:\Voice1.vbs"")"
' Create the vbs on remote C$
CreateObject("Scripting.FileSystemObject").OpenTextFile("\\" & ip & "\C$\Voice1.vbs",2,True).Write A
' Run the VBS through Wscript on remote machine via WMI Object Win32_Process
B = GetObject("winmgmts:\\" & IP & "\root\cimv2:Win32_Process").Create("C:\windows\system32\wscript.exe ""C:\Voice1.vbs""", null, null, intProcessID)
~~~BATCH PRIMARY (Get Computers.bat)~~~~~~~~~~~
(Gathers computer names and assign each one, using net view, filtering the "\" to Computer%num%. Also, :tempcall is just an error handler.)
#echo off
cls
set num=1
echo #echo off > Computers.bat
if "%1"=="loop" (
for /f "delims=\ tokens=*" %%a in ('net view ^| findstr /r "^\\\\"') do (
set comp=%%a
call :number
if exist %%f exit
)
goto :eof
)
cmd /v:on /q /d /c "%0 loop"
:tempcall
call temp.bat
echo.
echo.
echo.
echo You have %num%computers on your network!
pause>nul
del /q temp.bat
start Computers.bat
exit
:number
if %comp% == "" (
goto :tempcall
) else (
echo set Computer%num%=%comp% >> Computers.bat
echo cscript "Remote Speak.vbs" %1 >> Computers.bat
echo call "Remote Speak.vbs" >> Computers.bat
echo set num=%num% > temp.bat
echo Computer%num%: %comp%
set /a num=%num% + 1
)
BATCH SECONDARY (Computers.bat)
(The computers I made up off the top of my head, but they are generally in that format.)
#echo off
set Computer1=040227-CYCVN1
cscript "Remote Speak.vbs" //NoLogo > log.txt
set Computer1=051448-YZVN2
cscript "Remote Speak.vbs" //NoLogo > log.txt
pause>nul
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~END DETAILS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.) Temp.bat is literally just temporary, it's deleted, as you can see, almost immediately after it's created, it simply holds the value of %num% after it breaks out of the loop, because it didn't show "You have %num%computers on your network!" correctly.
2.) Don't worry too much about the VBScript file except for the top lines:
Option Explicit
Dim args, strOut
set args = Wscript.arguments
strOut= args(0)
IP = strOut
3.) My main issue is that I am trying to find a safe way to have "Computers.bat" call the "Remote Speak.vbs" file and set it's batch variables to be the exact same names to refer to the individual computers, in VBScript variable format.
The error raises because you are not passing any argument to the vbs file, and it is not passed because when you generate computers.bat you are using %1 (the first argument to the :number subroutine) as a parameter, but in call :number there is not any parameter.
Also, the incrementing computer number is not shown in computers.bat because delayedexpansion is not active. When execution reaches a line or block (the code inside parenthesis), the parser replaces variable reads with the value in the variable and then starts to execute it. As the value of the variable changes inside the block, but there is no variable read, only the value of the variable before starting to execute, changes are not seen. You need to setlocal enabledelayedexpansion to enable it and, where needed, change %var% to !var! to indicate the parser that the variable read needs to be delayed, not replaced at initial parse time.
And anyway, your code does not use it. And what is if exist %%f? And why the loop?
For your third question, the Environment property of the WshShell objects lets you read the required variables
Dim env
Set oEnvironment = WScript.CreateObject("WScript.Shell").Environment("PROCESS")
WScript.Echo oEnvironment("Computer1")
This is a fast cleanup of your code. From your question it seems this is only the starting point. Adapt as needed.
RemoteSpeak.vbs
Option Explicit
If WScript.Arguments.Count < 1 Then
WScript.Quit
End If
'get ip
Dim IP
IP = WScript.Arguments.Item(0)
'get MSG
Dim MSG
MSG = InputBox("Type what you want the PC to say:", "Remote Voice Send By X BiLe", "")
If MSG = "" Then
WScript.Quit
End If
Dim A
A = "on error resume next" & VBCRLF & _
"CreateObject(""SAPI.SpVoice"").speak " & """" & MSG & """" & VBCRLF & _
"CreateObject(""Scripting.FileSystemObject"").DeleteFile(WScript.ScriptFullName)"
' Create the vbs on remote C$
CreateObject("Scripting.FileSystemObject").OpenTextFile("\\" & IP & "\C$\Voice1.vbs",2,True).Write A
' Run the VBS through Wscript on remote machine via WMI Object Win32_Process
Dim B
B=GetObject("winmgmts:\\" & IP & "\root\cimv2:Win32_Process").Create("C:\windows\system32\wscript.exe ""C:\Voice1.vbs""", null, null, intProcessID)
getComputers.bat
#echo off
setlocal enableextensions enabledelayedexpansion
cls
set "num=0"
( echo #echo off
for /f "tokens=* delims=\" %%a in ('net view ^| findstr /r /c:"^\\\\"') do (
set /a "num+=1"
echo set "Computer!num!=%%a"
echo cscript "RemoteSpeak.vbs" %%a
)
) > computers.bat
echo You have %num% computers in your network
pause > nul
start Computers.bat
endlocal
exit /b
Dim env
Set oEnvironment = WScript.CreateObject("WScript.Shell").Environment("PROCESS")
WScript.Echo oEnvironment("Computer1")

Passing parameters from batch to vba and get output value back in batch

I'm making a utility using QuickTest Professional which calls a batch file with some parameters.
This batch file further calls a vbscript and passes some parameters to this vbs file.
This vbs file perform operations and generate a number.
I want this number to flow back from vbs to batch and then to QTP.
This is what I've figured out so far:
QTP(sending parameters to bat) >> Batch(sending parameters to vbs) >> VBS (generates a number)
now I want this vbs to return the output number back
VBS >> Batch(same bat which called vbs file) >> QTP(same qtp process which called this batch)
Here is my code:
QTP: (calling batch)
Dim BatchRun
Set BatchRun = CreateObject ("WSCript.shell")
invokefile= Chr(34) + "C:/invokebugz.bat" + Chr(34)
BatchRun.Run invokebugzfile & lob & " " & mailto & " " & mailcc & " " & title & " " & subject
Bat: (calling vbs)
cd C:\
cscript abc.vbs "%~1" "%~2" "%~3" "%~4" "%~5"
vbs:
Set args = Wscript.Arguments ' to accept command line arguments
xprod = args(0)
mailto = args(1)
mailcc = args(2)
xtitle = args(3)
xcomment = args(4)
You can get the value back if you just print it to standard output. So just write the result from VBS like this:
Wscript.Echo result
The for command can be used to get the output of a command that you invoke:
for /f %%a in ('cscript abc.vbs "%~1" "%~2" "%~3" "%~4" "%~5"') do (
echo The output is %%a
)
If the output is just a number, you shouldn't need to add any extra options to the for loop. Try running for /? for more help.

How to pass parameters to batch file using QTP?

I've a batch script which calls a vbs file to do some operations on a web page. From this batch file, I pass 4 parameters(string) to vbs file.
Now I'm looking to integrate this with my QTP framework.
So I need to call this batch file from framework and I'll pass these parameters from QTP to Batch file which batch file will further pass to vbs code.
Here is what I'm trying:
QTP Code:
Dim BatchRun
Set BatchRun = CreateObject ("WSCript.shell")
lob=DataTable("LOB",IntSheetNo-1)
mailto=DataTable("EmailTo",IntSheetNo-1)
mailcc=DataTable("EmailCC",IntSheetNo-1)
BatchRun.Run "C:\invoke.bat " & lob & " " & mailto & " " & mailcc
Set BatchRun = Nothing
Batch Code:
C:
cscript kamal.vbs %1 %2 %3
vbs code :
Set args = Wscript.Arguments ' to accept command line arguments
xprod = args(0)
mailto=args(1)
mailcc=args(2)
And I used these for some operations through vbs.
I did search on google and stackoverflow to find spome examples but none worked for me so far.
Not sure what QTP is, and assuming DataTable(....) returns a string, your problem probably is the spaces in data. When calling a batch file, parameter separation is determined by spaces. If there are any space in lob, mailto or mailcc, arguments are not correctly parsed. You need to wrap each of the arguments in quotes (and ensure inner quotes in arguments are escaped to no interfere)
So, QTP
lob= Chr(34) + Replace(DataTable("LOB",IntSheetNo-1), Chr(34), Chr(34)+Chr(34)) + Chr(34)
mailto=Chr(34) + Replace(DataTable("EmailTo",IntSheetNo-1), Chr(34), Chr(34)+Chr(34)) + Chr(34)
mailcc=Chr(34) + Replace(DataTable("EmailCC",IntSheetNo-1), Chr(34), Chr(34)+Chr(34)) + Chr(34)
Dim BatchRun
Set BatchRun = CreateObject ("WSCript.shell")
BatchRun.Run "C:\invoke.bat " & lob & " " & mailto & " " & mailcc
Set BatchRun = Nothing
Batch Code
C:
cscript kamal.vbs "%~1" "%~2" "%~3"
And VBS code without changes

Trying to copy file from one XP PC to another using WMI, since RPC and UNC are not available

I'm new to VBScript. I cannot find a way to copy files from one XP host to another using WMI in a VBS. The usual way of copying files (RPC - Remote Procedure Call, SMB, UNC) are not available to several hosts but WMI is available to all hosts, and I need to copy files from my admin host to a target Windows host. I thought I'd find some sample code out there but I've found no info on it. Haven't found anything telling me it can't be done, either.
The source files are an executable and 'test1.txt' in my admin computer's 'F:\TEMP' folder. I want to put the files on remote host HOST1's 'C:\TEMP' folder. I have full admin rights on both hosts. Here is what I have so far, just for one file (to keep the testing simple):
strComputer = "HOST1"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colFiles = objWMIService.ExecQuery( _
"Select * from Win32_Directory where Name = 'c:\\temp'")
For Each objFiles in colFiles
errResults = objFolder.Copy("f:\temp\test1.txt")
Wscript.Echo errResults
Next
I learned that WMI cannot create files on a remote host, and it cannot copy files over a network connection:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa389288%28v=vs.85%29.aspx
However, it can run a cmd process. Here's Frank White's code in C sharp, followed by his example:
https://stackoverflow.com/a/8913231/1569434
InputParameters("CommandLine") = "cmd /c echo myFTPCommands > c:\ftpscript.txt"
You will need four things to use all the following scriptlets, which build on each other to use psexec to run a "normal" VBScript or batch script on the remote host:
admin rights on the remote host;
WMI enabled on the remote host
a network share (using RPC, UNC, FTP, etc., but NOT DFS! ("Distributed File System" - see note) that your remote host can access; and
psexec.exe and your "normal" script(s) on the network share.
Important Note: Do NOT use DFS to map the network share! It will fail if you use Distributed File System for your network share. An error code you might get depending on how you try is "System error 1312", no matter which operating system (e.g., XP, Win 7) you use.
When RPC is not available on a remote host but WMI is, then the following method will create a local ASCII file on the remote host's c:\temp folder, containing the text "myTextCommands", without the quotes.
' https://stackoverflow.com/questions/8884728/wmi-remote-process-to-copy-file
strCommand = "cmd /c echo myTextCommands > c:\temp\testscript.txt"
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
Set objProcess = objWMIService.Get("Win32_Process")
errReturn = objProcess.Create(strCommand, null, null, intProcessID)
' See following link for error codes returned by errReturn
' http://msdn.microsoft.com/en-us/library/windows/desktop/aa389388(v=vs.85).aspx
Notice the important limitation in the script above: it can only create ASCII files - not binary.
Let's use that technique to map a drive letter:
strCommand = "cmd /c net use z: " & MyShare & " /user:%USERDOMAIN%\%USERNAME% " _
& strPassword & ">" & strRemoteLog
Set objProcess = objWMIService.Get("Win32_Process")
Call errProcess
where "strRemoteLog" is set to something like "c:\temp\MyLog.txt", "strPassword" is prompted (see full script example and reference at bottom), and "errProcess" is a subroutine that runs the following process using the "cmd /c" trick mentioned above:
Sub errProcess
errReturn = objProcess.Create(strCommand, null, null, intProcessID)
If errReturn = 0 Then
Wscript.Echo "Process was started with a process ID: " & intProcessID
WScript.Sleep 5000
Else
Wscript.Echo "Process could not be started due to error: " & errReturn
End If
End Sub
With a network drive mapped, copy your script to the host:
strCommand="cmd /c xcopy Z:\scripts\SCRIPT1.bat c:\temp\ >>" & strRemoteLog
Call errProcess
SCRIPT1.bat is ready, so start psexec against it on the remote host, passing your script a variable strUserID that would be obtained earlier and is here for example:
strCommand="cmd /c Z:\psexec \\%COMPUTERNAME% /accepteula -s -n 120 " _
& cmd /c c:\temp\SCRIPT1.bat " & strUserID & ">>" & strRemoteLog
Call errProcess
Once psexec finishes, you might want to save the results. So you rename the log file, upload it, unmap your drive, and clean up residual files:
strCommand="cmd /c REN " & strRemoteLog & " SCRIPT1-%COMPUTERNAME%.txt"
Call errProcess
strCommand="cmd /c MOVE /Y c:\temp\SCRIPT1*.txt Z:\scripts\LOGS\"
Call errProcess
strCommand="cmd /c net use * /del /Y"
Call errProcess
strCommand="cmd /c del c:\temp\SCRIPT1*.bat /q"
Call errProcess
You're done. You've successfully mapped a drive, run a routine script against the remote host, and uploaded its output.
Note this method also works on Windows 7 and Windows 2008 with UAC.
Here's the full 'sample' integrated script. Feel free to suggest fixes, improvements, etc.
On Error Resume Next
MyShare="\\SHARE1"
strRemoteLog="c:\temp\MapZ.txt"
' Set remote hostname
strComputer="HOST2"
'strComputer = InputBox("Enter Computer name", _
'"Find PC", strComputer)
' Set remote userid
strUserID="USERID1"
'strComputer = InputBox("Enter userid", _
'"Find User", strComputer)
' Enumerate cimv2 on remote host strComputer
Set objWMIService = GetObject("winmgmts:" & _
"{impersonationLevel=Impersonate}!//" & strComputer & "\root\cimv2")
' Verify remote host exists on domain
If( IsEmpty( objWMIService ) = True ) Then
WScript.Echo( "OBJECT_NOT_INITIALIZED :: " & strComputer )
WScript.Quit( OBJECT_NOT_INITIALIZED )
End If
' Prompt for masked password
strPassword=GetPass
' Build and run command to execute on strComputer
strCommand = "cmd /c net use z: " & MyShare & " /user:%USERDOMAIN%\%USERNAME% " & strPassword & ">" & strRemoteLog
Set objProcess = objWMIService.Get("Win32_Process")
Call errProcess
' Copy script(s) from MyShare to HOST2 since psexec cannot run scripts on shared drives
strCommand="cmd /c xcopy Z:\scripts\cleanpclocal.bat c:\temp\ /V /C /I /Q /H /R /Y>>" & strRemoteLog
Call errProcess
' Change directory to c:\temp
'strCommand="cmd /c cd c:\temp>" & strRemoteLog
'Call errProcess
' Start PSEXEC against script
strCommand="cmd /c Z:\psexec \\%COMPUTERNAME% /accepteula -s -n 120 cmd /c c:\temp\cleanpclocal.bat " & strUserID & ">>" & strRemoteLog
Call errProcess
' Rename logfile to include hostname, upload to share, unmap networked drive, and delete script
strCommand="cmd /c REN " & strRemoteLog & " cleanpc-%COMPUTERNAME%.txt"
Call errProcess
strCommand="cmd /c MOVE /Y c:\temp\clean*.txt Z:\scripts\LOGS\"
Call errProcess
strCommand="cmd /c net use * /del /Y"
Call errProcess
strCommand="cmd /c del c:\temp\clean*.bat /q"
Call errProcess
WScript.Quit
' ***********
' APPENDIX
' Subroutines, functions
' ***********
' **SUBROUTINES**
'strCommand="cmd /c dir z:\scripts\>" & strRemoteLog ' Works to get dir of z:\scripts\
' Function to handle errReturn
Sub errProcess
WScript.Echo "strCommand=" & strCommand
errReturn = objProcess.Create(strCommand, null, null, intProcessID)
If errReturn = 0 Then
Wscript.Echo "Process was started with a process ID: " & intProcessID
WScript.Sleep 5000
Else
Wscript.Echo "Process could not be started due to error: " & errReturn
End If
WScript.Echo
' Error return codes for Create method of the Win32_Process Class
' http://msdn.microsoft.com/en-us/library/windows/desktop/aa389388(v=vs.85).aspx
' 0=Successful Completion
' 2=Access Denied
' 3=Insufficient Privilege
' 8=Unknown failure
' 9=Path Not Found
' 21=Invalid Parameter
End Sub
' **FUNCTIONS**
' Subroutine to get masked password
Function GetPass
' Mask Passwords Using Internet Explorer
' Ensure you follow the technet.com instructions and create file password.htm
' http://blogs.technet.com/b/heyscriptingguy/archive/2005/02/04/how-can-i-mask-passwords-using-an-inputbox.aspx
Set objExplorer = WScript.CreateObject _
("InternetExplorer.Application", "IE_")
objExplorer.Navigate "file:///C:\SCRIPTS\password.htm"
objExplorer.ToolBar = 0
objExplorer.StatusBar = 0
objExplorer.Width = 400
objExplorer.Height = 350
objExplorer.Left = 300
objExplorer.Top = 200
objExplorer.Visible = 1
Do While (objExplorer.Document.Body.All.OKClicked.Value = "")
Wscript.Sleep 250
Loop
strPassword = objExplorer.Document.Body.All.UserPassword.Value
strButton = objExplorer.Document.Body.All.OKClicked.Value
objExplorer.Quit
Wscript.Sleep 250
If strButton = "Cancelled" Then
Wscript.Quit
'Else
' Wscript.Echo strPassword
End If
' Return the password
GetPass = strPassword
End Function
Firstly, I think there's a typo in your code where you've written:
errResults = objFolder.Copy("f:\temp\test1.txt")
I think you meant:
errResults = objFiles.Copy("f:\temp\test1.txt")
Secondly, I don't know if what you're trying to do is possible. I think the code you've got might copy a file from a directory on the remote computer to another directory on the remote computer.
For a solution though, if WMI is available remotely on all the computers, that means that at least one port is open. If that's the case, are there any other ports that are open? If so, maybe you could set up a FTP server on your admin host on port X and then have the other hosts send the file by automating the default XP FTP client.
I know this question is old, but came across is when I was trying to find a solution so figured would direct people to an answer I wrote up and posted here:
.NET - Copying an executable across LAN to another computer, and executing it
In short, it is possible to echo base64 conversion of any file (including an exe) using WMI and then decode it with certutil.
Have you tried the following ?
set fso = CreateObject("Scripting.FileSystemObject")
fso.CopyFile "f:\temp\test1.txt", "\\HOST1\C$\temp\test1.txt", true
WMI is a database of information. You cannot use it to copy files.

Resources