"connection.Children(0)" triggers "The enumerator of the collection cannot find en element with the specified index." - vbscript

I am using a VBScript to login automatically into SAP GUI.
It opens automatically the SAP GUI window, it loads the SAP server, but it doesn't populate automatically the user and password fields (remain blank).
It also gives a script error on line 52, char 4:
The enumerator of the collection cannot find en element with the specified index.
The code is the following:
REM The following script was written to log into the SAP server automatically.
REM To view historical information and credit for this script please see
REM the following thread on the SAP Community Network:
REM http://scn.sap.com/thread/3763970
REM This script was last updated by Paul Street on 7/1/15
REM Directives
Option Explicit
REM Variables! Must declare before using because of Option Explicit
Dim WSHShell, SAPGUIPath, SID, InstanceNo, WinTitle, SapGuiAuto, application, connection, session
REM Main
Set WSHShell = WScript.CreateObject("WScript.Shell")
If IsObject(WSHShell) Then
REM Set the path to the SAP GUI directory
SAPGUIPath = "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\"
REM Set the SAP system ID
SID = "eaiserver.domain.com"
REM Set the instance number of the SAP system
InstanceNo = "38"
REM Starts the SAP GUI
WSHShell.Exec SAPGUIPath & "SAPgui.exe " & SID & " " & _
InstanceNo
REM Set the title of the SAP GUI window here
WinTitle = "SAP"
While Not WSHShell.AppActivate(WinTitle)
WScript.Sleep 250
Wend
Set WSHShell = Nothing
End If
REM Remove this if you need to test the above script and want a message box at the end launching the login screen.
REM MsgBox "Here now your script..."
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/txtRSYST-MANDT").Text = "100"
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "I'veInsertedtheCorrectUsernameHere"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "I'veInsertedtheCorrectPassHere"
session.findById("wnd[0]/usr/txtRSYST-LANGU").Text = "PT"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").setFocus
session.findById("wnd[0]/usr/pwdRSYST-BCODE").caretPosition = 10
session.findById("wnd[0]").sendVKey 0
Thanks for the help!

I am using the exact same script, which I found somewhere on the SAP help forums.
When I've encountered this issue before it's usually because the SAP GUI window was loaded AFTER lines
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "username"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "password"
There are two ways to fix this particular script. One is to add a MsgBox that will pause the script, but give SAP GUI enough time to load. The other is to add WScript.Sleep(<a few seconds>) to allow SAP GUI to load. Like so ...
Note that the below code has BOTH examples, but only 1 is necessary. I prefer the .Sleep() because it requires no external input from a user.
If IsObject(WSHShell) Then
' Removed for clarity
End If
MsgBox "Click OK to continue" ' <-- MsgBox to pause script
WScript.Sleep(5000) ' <--- Wait 5 seconds for SAP GUI to load
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").resizeWorkingPane 164,40,false
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "username"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "password"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").setFocus
session.findById("wnd[0]/usr/pwdRSYST-BCODE").caretPosition = 14
session.findById("wnd[0]").sendVKey 0
And of course, storing username and password in plain text is not a good practice. However, obfuscating passwords with the VBScript InputBox() is not possible. You will have to use the command line, or create an IE object which is outside the scope of this question

Here's some VBS code that tries to wait for SAP to login and load properly. It worked well for me so far.
Function SAP_start_and_login(connection_string, use_sso, user, pass)
WScript.Echo "executing function SAP_start_and_login()"
REM Variables! Must declare before using because of Option Explicit
Dim WSHShell, SAPGUIPath
REM Main
Set WSHShell = WScript.CreateObject("WScript.Shell")
If IsObject(WSHShell) Then
REM Set the path to the SAP GUI directory
SAPGUIPath = "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\"
REM Starts the SAP GUI
if use_sso then
WSHShell.Exec SAPGUIPath & "sapshcut.exe -client={your_client} -sysname=whatevah -gui=" & connection_string & " -snc_name={your_snc_name} -snc_qop={your_snc_qop}"
else
WSHShell.Exec SAPGUIPath & "sapshcut.exe -client={your_client} -sysname=whatevah -gui=" & connection_string & " -user=" & user & " -pw=" & pass
end if
REM WSHShell.Exec SAPGUIPath & "saplogon.exe """ & system & """"
Set WSHShell = Nothing
WScript.Echo "{waiting for SAP to finish loading..}"
SAP_start_and_login = WaitForSAP(connection_string, 50)
WScript.Sleep 1000
End If
End Function
Function CheckSapIsRunning(connection_string)
Running = False
Ready = False
If Not IsObject(application) Then
On Error Resume Next
Set SapGuiAuto = GetObject("SAPGUI")
If (Err.Number <> 0) Then
WScript.Echo "SAPGUI object not found yet"
' Error raised, object not found.
' Restore normal error handling.
On Error GoTo 0
Else
'WScript.Echo "einai ok"
' Object found.
' Restore normal error handling.
On Error GoTo 0
Set application = SapGuiAuto.GetScriptingEngine
If application.Connections.Count() > 0 Then
For i = 0 To (application.Connections.Count()-1)
REM WScript.Echo i
Set Connection = application.Children(0+i)
Conn = Connection.ConnectionString()
REM WScript.Echo Conn
If InStr(Conn, connection_string) Then
Running = True
Exit For
End If
Next
End If
If Running Then
REM WScript.Echo connection_string + " is running!"
REM WScript.Echo "sessions="+CStr(connection.Children.Count)
If Not IsObject(session) Then
if connection.Children.Count > 0 then
Set session = connection.Children(0)
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
If not session.Busy then
Ready=True
REM WScript.Echo connection_string + " session is ready!"
Dim sapWindow
set sapWindow = session.findById("wnd[0]", False)
if sapWindow is Nothing then
WScript.Echo connection_string + " sap window element not there yet"
else
WScript.Echo connection_string + " is loaded and visible!"
end if
Else
WScript.Echo connection_string + " session is busy!"
end if
else
WScript.Echo connection_string + " session not loaded yet!"
end if
End If
else
WScript.Echo connection_string + " not running!"
End If
End If
End If
REM WScript.Echo application.Connections.Count()
CheckSapIsRunning = Ready
End Function
Function WaitForSAP(connection_string, timeout)
counter = 0
returnValue = False
While NOT CheckSapIsRunning(connection_string) AND counter < timeout
counter = counter + 1
WScript.Sleep 1000
REM WScript.Echo connection_string + " is not ready"
WEnd
if counter = timeout then
WScript.Echo "timeout of " + CStr(timeout) + " seconds reached."
else
returnValue = True
end if
WaitForSAP = returnValue
End Function
This can be used like this
If SAP_start_and_login(connection_string, use_sso, username, password) Then
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
...{the rest of your recorded script}
Else
WScript.Echo "Could not get a functioning SAP session"
WScript.Quit 1
End If
I'm using sapshcut.exe because it was easy to have both SSO and non SSO in a similar manner. The connection string is important in order to distinguish and identify the instance of SAP that you want to use in the rest of the script. It can be found from your current shortcut along with the SSO parameters that you might be using. If the SSO is true the user and pass parameters are not used. The timeout is also useful to avoid an endless loop if SAP is down or unreachable.
This solution does not need a static sleep in the script in order to wait for SAP to load which could prevent issues if SAP took more than expected to load. Also no time is wasted if it is loaded sooner than expected.

Related

Vbscript to run .Bat file with parameters and search for error in result txt file

I am preparing vbscript to run bat files where bat file name contains version number, Script have to search for bat file with matching version name . Once Ran,The result Text file will be generated with same version number. I have to search for Text file with same version number and read the txt file for error or msg, if error found i want to display it.
I know my requirement is little too much.
But I am finding little difficulty in debugging the code.I am stuck.
Can any one help me to resolve the issue.
Thank You
here is my script,
I am passing values for sql query from excel sheet.
Dim Ver, Version_Number
Dim con
Dim rs
Set con=createobject("adodb.connection")
Set rs=Createobject("adodb.recordset")
Set PinXL = CreateObject("Excel.application")
Set PinWB = PinXL.Workbooks.Open("C:\maspects\Trial.xls") '// Login and Enable Debug Window in application
Set PinWS = PinWB.Worksheets("Sheet1")
varr = Cstr(PinWS.Cells(2,1).Value)
varr1 = trim(varr)
usename = Cstr(PinWS.Cells(2,2).Value)
UN = trim(usename)
password = Cstr(PinWS.Cells(2,3).Value)
PWD = trim(password)
IrisDB = Cstr(PinWS.Cells(2,4).Value)
DB = trim(IrisDB)
Site_Name = Cstr(PinWS.Cells(2,5).Value)
Site = trim(Site_Name)
con.open"provider=sqloledb.1;server=" & varr1 & ";uid=" & UN & ";pwd=" & PWD & ";database=" & DB &""
Wscript.sleep 1000*3
rs.Open "select * from tblSettingsUnique where [Setting Name] like '%Revision%'" ,con
Wscript.sleep 1000*2
Version_Number = rs.Fields("Setting Value")
Ver = Version_Number
msgbox Ver
Call Execute
PinWB.Save
PinWB.Close
PinXL.Quit
Wscript.Quit
Function Execute
If Ver < PinWS.Cells(2,6).Value = "True" Then ' if Ver is less than Cell(2,6) value then application should come out of loop
For i = Ver to PinWS.Cells(2,6).Value step 1
msgbox i
Set WShell = CreateObject("WScript.Shell")
For each f in Wshell.Getfolder("C:\maspects\DB_script").Files
BatFile = instr(f.File , "4_0_"&i )
WShell.Run ("CMD /K C:\maspects\DB_script\"&batFile &".bat" & Varr1 &" "& UN &" "& password )
Call msg
Next
Next
End If
End Function
Function msg
Set TxtObject = CreateObject("scripting.FileSystemObject")
For each ResFile in TxtObject.GetFolder("C:\maspects\DB_script").Files
TargetFile = InStr(ResFile.File , "4_0_"&i )
Set TxtFile = TxtObject.openTextFile("C:\maspects\DB_script\"&TargetFile, 1 ,true)
Do until TxtFile.AtEndOfStream
For each F in TxtFile.Readline
if InStr (F,"msg" ) = "True" and InStr (F,"msg 207" )= "False" Then
msgbox "Error in:"&TargetFile
React =Cint(Inputbox("Go through the Result file:"&TargetFile &"Enter '1' to Continue '0' to Quit"))
If React = "0" Then
TextObject.Close
Wscript.Quit
End if
End If
Next
Loop
TextObject.Close
Next
End Function

Run script in background

I want to run following script as scheduled task on Windows 7 in background. Now, script displays cmd window and, can I run script without visible cmd window?
Option Explicit
Dim WshShell, oExec
Dim RegexParse
Dim hasError : hasError = 0
Set WshShell = WScript.CreateObject("WScript.Shell")
Set RegexParse = New RegExp
Set oExec = WshShell.Exec("%comspec% /c echo list volume | diskpart.exe")
RegexParse.Pattern = "\s\s(Volume\s\d)\s+([A-Z])\s+(.*)\s\s(NTFS|FAT)\s+(Mirror|RAID-5)\s+(\d+)\s+(..)\s\s([A-Za-z]*\s?[A-Za-z]*)(\s\s)*.*"
While Not oExec.StdOut.AtEndOfStream
Dim regexMatches
Dim Volume, Drive, Description, Redundancy, RaidStatus
Dim CurrentLine : CurrentLine = oExec.StdOut.ReadLine
Set regexMatches = RegexParse.Execute(CurrentLine)
If (regexMatches.Count > 0) Then
Dim match
Set match = regexMatches(0)
If match.SubMatches.Count >= 8 Then
Volume = match.SubMatches(0)
Drive = match.SubMatches(1)
Description = Trim(match.SubMatches(2))
Redundancy = match.SubMatches(4)
RaidStatus = Trim(match.SubMatches(7))
End If
If RaidStatus <> "Healthy" Then
hasError = 1
'WScript.StdOut.Write "WARNING "
MsgBox "Status of " & Redundancy & " " & Drive & ": (" & Description & ") is """ & RaidStatus & """", 16, "RAID error"
End If
End If
Wend
WScript.Quit(hasError)
Thanks a lot
Option 1 - If the task is running under your user credentials (if not, msgbox will not be visible)
There are two possible sources for the cmd window.
a) The script itself. If the task is executing cscript, the console window will be visible, avoid it calling wscript instead
b) The Shell.exec call. The only way to hide this window is to start the calling script hidden. On start of your script test for the presence of certain argument. If not present, make the script call itself with the argument, using Run method of the WshShell object, and indicating to run the script with hidden window. Second instance of the script will start with the special parameter, so it will run, but this time windows will be hidden.
Option 2 - Running the task under system credentials.
In this case, no window will be visible. All will be running in a separate session. BUT msgbox will not be seen. Change MsgBox call with a call to msg.exe and send a message to current console user.

VBS To Event Log

I have a script that I am currently using to check when that network goes up or down. Its writing to a pinglog.txt .
For the life of me I can not figure out how to get it to write to the event log when the network goes down. Where it says:
Call logme(Time & " - " & machine & " is not responding to ping, CALL FOR
HELP!!!!",strLogFile)
Thats what I need to write to the Event Log "Machine is not repsonding to ping, CALL FOR HELP!!!!
'Ping multiple computers and log when one doesn't respond.
'################### Configuration #######################
'Enter the IPs or machine names on the line below separated by a semicolon
strMachines = "4.2.2.2;8.8.8.8;8.8.4.4"
'Make sure that this log file exists, if not, the script will fail.
strLogFile = "c:\logs\pinglog.txt"
'################### End Configuration ###################
'The default application for .vbs is wscript. If you double-click on the script,
'this little routine will capture it, and run it in a command shell with cscript.
If Right(WScript.FullName,Len(WScript.FullName) - Len(WScript.Path)) <> "\cscript.exe" Then
Set objWMIService = GetObject("winmgmts: {impersonationLevel=impersonate}!\\.\root\cimv2")
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
objProcess.Create WScript.Path + "\cscript.exe """ + WScript.ScriptFullName + """", Null, objConfig, intProcessID
WScript.Quit
End If
Const ForAppending = 8
Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strLogFile) Then
Set objFolder = objFSO.GetFile(strLogFile)
Else
Wscript.Echo "Log file does not exist. Please create " & strLogFile
WScript.Quit
End If
aMachines = Split(strMachines, ";")
Do While True
For Each machine In aMachines
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}")._
ExecQuery("select * from Win32_PingStatus where address = '"_
& machine & "'")
For Each objStatus In objPing
If IsNull(objStatus.StatusCode) Or objStatus.StatusCode<>0 Then
Call logme(Time & " - " & machine & " is not responding to ping, CALL FOR
HELP!!!!",strLogFile)
Else
WScript.Echo(Time & " + " & machine & " is responding to ping, we are good")
End If
Next
Next
WScript.Sleep 5000
Loop
Sub logme(message,logfile)
Set objTextFile = objFSO.OpenTextFile(logfile, ForAppending, True)
objtextfile.WriteLine(message)
WScript.Echo(message)
objTextFile.Close
End Sub
Sorry about the spacing in the code. Thanks for the help
Use the WshShell object:
object.LogEvent(intType, strMessage [,strTarget])
object WshShell object.
intType Integer value representing the event type.
strMessage String value containing the log entry text.
strTarget Optional. String value indicating the name of the computer
system where the event log is stored (the default is the local
computer system). Applies to Windows NT/2000 only.
Like so:
Option Explicit
Dim shl
Set shl = CreateObject("WScript.Shell")
Call shl.LogEvent(1,"Some Error Message")
Set shl = Nothing
WScript.Quit
The first argument to LogEvent is an event type:
0 SUCCESS
1 ERROR
2 WARNING
4 INFORMATION
8 AUDIT_SUCCESS
16 AUDIT_FAILURE
EDIT: more detail
Replace your entire 'logme' sub-routine with this
Sub logme(t,m)
Dim shl
Set shl = CreateObject("WScript.Shell")
Call shl.LogEvent(t,m)
Set shl = Nothing
End Sub
Then change this line:
Call logme(Time & " - " & machine & " is not responding to ping, CALL FOR HELP!!!!",strLogFile)
To:
Call logme(1, machine & " is not responding to ping, CALL FOR HELP!!!!")

VBS script error

Im getting this error when i try to run my vbs script,
object doesnt support this property or method
My vbs code is
Rem -- This example will show you how to create a very simple runonce configuration.
Rem -- Get current path of this script.
Set fso = CreateObject("Scripting.FileSystemObject")
currentdir = fso.GetAbsolutePathName(".")
Rem -- Read the info xml
Set xmldom = CreateObject("MSXML.DOMDocument")
xmldom.Load("c:\Montupet\PDF" & "\info.xml")
Rem -- Get the program id of the automation object.
progid = xmldom.SelectSingleNode("/xml/progid").text
Rem -- Create the COM object to control the printer.
set obj = CreateObject(progid)
Rem -- Get the default printer name.
Rem -- You can override this setting to specify a specific printer.
printername = "PDF Writer - bioPDF"
runonce = obj.GetSettingsFileName(true)
^
Error here
set oArgs=wscript.Arguments
Rem -- Print all the files in the 'in' folder
dim file_name, template
dim command_line_args
set command_line_args = wscript.Arguments
'Check if any Arguments have been passed to our script.
if command_line_args.count > 0 then
file_name = command_line_args(0)
template = command_line_args(1)
Set oWd = CreateObject("Word.Application")
oWd.Visible = False
wordname = """" & "c:\MTMS\MTMSPRT\" & file_name & """"
wscript.echo wordname
Set oDoc = oWd.Documents.Open(wordname)
Set oPS = oDoc.PageSetup
' Reduce the margins to .5" (36 points)
oPS.LeftMargin = 8.4
oPS.RightMargin = 0.2
'Save changes to doc on closing and quit Word
oDoc.Saveas wordname , 0
wscript.echo "Saved"
oDoc.Close
wscript.echo "close"
oWd.Quit
wscript.echo "Quit"
Set oWd = Nothing
Set objShell = Nothing
wscript.echo "Cleared Word"
Set oWd = Nothing
Set objShell = Nothing
output = "c:\MTMS\MTMSPRT\PDFs\" & Replace(ucase(file_name), "DOC", "") & "PDF"
Rem -- Set the values
obj.Init
obj.SetValue "Output", output
obj.SetValue "ShowSettings", "never"
obj.SetValue "ShowPDF", "no"
obj.SetValue "ShowProgress", "no"
obj.SetValue "ShowProgressFinished", "no"
obj.SetValue "SuppressErrors", "no"
obj.SetValue "ConfirmOverwrite", "no"
obj.SetValue "superimpose", template
Rem -- Write settings to the runonce-Invoice.ini
obj.WriteSettings True
wscript.echo "runonce created"
Rem -- Print the document
printfile = "c:\MTMS\MTMSPRT\" & file_name
cmd = """" & "c:\Montupet\PDF\printto.exe"" """ & printfile & """ """ & printername & """"
wscript.echo "printfile line setup"
Set WshShell = WScript.CreateObject("WScript.Shell")
ret = WshShell.Run(cmd, 1, true)
wscript.echo "shell run start"
Rem -- Wait until the runonce is removed.
Rem -- When the runonce is removed it means that the gui.exe program
rem -- has picked up the print job and is ready for the next.
While fso.fileexists(runonce)
wscript.echo "checking for runonce"
Rem -- Wait for some milliseconds before testing again
wscript.sleep 100
Wend
wscript.echo "runonce gone"
end if
Rem -- Dispose the printer control object
set obj = Nothing
Judging by this blog post for VB6,
runonce = obj.GetSettingsFileName(true)
should instead be
runonce = obj.GetSettingsFilePath(true)
The BioPDF website has a reference which might help further.

VB script to run a Query

I am trying to connect command prompt through VB script and further its connecting with Oracle enviroment to execute some reports of Oracle discoverer.
But the problem is with this VB script only.
line 2: for establishing the connection.
line 7:fetching the current REQUEST_ID.
line 16:XXDIS_EXPORT_CMD_V is a view and cmd is a column.which select a value like this for corresponding REQUEST_ID.
/CONNECT DISCADMIN:"FAI Financials Intelligence"/discbi#deverp /OPENDB "1 Scheduling" /SHEET "Sheet_1" /EXPORT HTML o27673334.out /LOGFILE l27673334.log /BATCH
In the end i want to execute this cmd using VBScript.
Error coming :
"In line 32 tkgoShell was not
recognized"
This is My code:
' Process job
Set objADO =CreateObject("ADODB.Connection")
objADO.Open "Driver={Microsoft ODBC for Oracle}; CONNECTSTRING=deverp; UID=apps; PWD=apps11i;"
MsgBox "Connection Established to Server.", vbExclamation + vbOKOnly, "System"
Do While True
' Check if there is a job to process
Set moRS=objADO.execute("SELECT apps.xxdis_schedule_pkg.start_job REQUEST_ID FROM dual")
moRS.MoveFirst
msRequest = moRS("REQUEST_ID")
'MsgBox msRequest,msRequest
' If no jobs then exit
' If msRequest = "0" Then
Exit Do
' End If
loop
Set moRS=objADO.execute("SELECT cmd EXPORT_CMD FROM apps.xxdis_export_cmd_v " & _
"WHERE request_id = " & msRequest)
MsgBox msRequest,msRequest
moRS.MoveFirst
msExpCmd = moRS("EXPORT_CMD")
' write command into a temporary file
msCmdFile = "r" & msRequest & ".cmd"
dim moOutputStream,filesys,msCommand
Set filesys = CreateObject("Scripting.FileSystemObject")
Set moOutputStream = filesys.CreateTextFile(msCmdFile, True)
' Substitute $SAMBA$ and $TNS$ locally configured variables
moOutputStream.Write Replace(Replace(msCmd, "$SAMBA$", gsOutDir),_
"$TNS$", gsInstance) & vbCRLF
moOutputStream.Close
' Call Discoverer to process the command
msCommand = gsBinDir & gsDiscoExe & " /EUL " & gsEUL & " /CMDFILE " & msCmdFile
Call tkgoShell.Run (msCommand, 1, true)
If I understand your code correctly I can't see anywhere where you're actually creating the tkgoShell.
Try inserting the following 2 rows before your last line:
Dim tkgoShell
Set tkgoShell = WScript.CreateObject ("WScript.Shell")
See here for more information about Shell.Run.

Resources