HTML within VBScript as a popup - html

I've looked at Use HTML tags in VBScript and How can I call a vbscript function from html?, but I can't see what is wrong with my code. Can someone look it over and let me know why, when I click the OK button, the window doesn't close? I commented some lines out that I've tried and didn't work.
Dim objIE, objShell
Dim strDX
Set objIE = CreateObject("InternetExplorer.Application")
Set objShell = CreateObject("WScript.Shell")
strDX = "AT-0125B"
objIE.Navigate "about:blank"
objIE.Document.Title = "Covered Diagnosis"
objIE.ToolBar = False
objIE.Resizable = False
objIE.StatusBar = False
objIE.Width = 350
objIE.Height = 200
'objIE.Scrollbars="no"
' Center the Window on the screen
With objIE.Document.ParentWindow.Screen
objIE.Left = (.AvailWidth - objIE.Width ) \ 2
objIE.Top = (.Availheight - objIE.Height) \ 2
End With
objIE.document.body.innerHTML = "<b>" & strDX & " is a covered diagnosis code.</b><p> </p>" & _
"<center><input type='submit' value='OK' onclick='VBScript:ClickedOk()'></center>" & _
"<input type='hidden' id='OK' name='OK' value='0'>"
objIE.Visible = True
'objShell.AppActivate "Covered Diagnosis"
'MsgBox objIE.Document.All.OK.Value
Function ClickedOk
'If objIE.Document.All.OK.Value = 1 Then
'objIE.Document.All.OK.Value = 0
'objShell.AppActivate "Covered Diagnosis"
'objIE.Quit
Window.Close()
'End If
End Function

The ClickedOk() function is not part of the HTML source code of the new window. Your script starts a new Internet Explorer process, but HTML (or script) code in that process cannot use code from another process (in this case the script process):
yourscript.vbs --> ClickedOk()
| ^
| |
| X
v |
iexplore.exe --> <input onclick='VBScript:ClickedOk()'>
You'd need IPC methods for communicating with other processes, but browsers usually restrict this kind of access due to security considerations.
So, when you click 'OK', it looks for a ClickedOK function and cannot find it. Thus it will not work.
To make it work, try something like this:
objIE.document.body.innerHTML = "<b>" & strDX & " is a covered diagnosis code.</b><p> </p>" & _
"<center><input type='submit' value='OK' onclick='self.close();'></center>" & _
"<input type='hidden' id='OK' name='OK' value='0'>"

Related

VBA error when triggering "change" event on IE input field

I'm trying to use VBA to access an internal web page using Internet Explorer, open a search window, enter search parameters and run the search. My code will click all of the buttons, find all of the text boxes and enter the parameters. But, it does not recognize any of the parameters entered using ".value" (i.e., objElement.value = "1234567"). I have written the code based on what I have read in this forum and a number of others but, obviously, I'm still missing something. When it tries to trigger the "change" event, I receive either an Error 438 - Object Doesn't Support this Property or Method, or an Error 5 - Invalid Procedure Call or Argument. The error depends on whether I use dispatchEvent or FireEvent and whether I use the collection or the element within the collection as the object. My guess is the problem lies with my declarations but, I tried a few different ones, and still get the errors.
Unfortunately, this is accessing an internal site so you won't be able to run the code. I'm hoping someone can just take a look and point me in the right direction.
Dim EPA As String
Dim EPANumb As Integer
Dim EPAList() As String
Dim PrjCnt As Long
Dim PrjList As String
Dim WS As Worksheet
Dim IE As InternetExplorerMedium
Dim URL As String
Dim HWNDSrc As Long
Dim objCollection As Object
Dim objElement As Object
Dim objEvent As Object
Dim oHtml As HTMLDocument
Dim HTMLtags As IHTMLElementCollection
'Pull list of project numbers and enter into array
fn = ThisWorkbook.Name
EPANumb = WorksheetFunction.CountA(Worksheets("Instructions").Range("B:B"))
EPANumb = EPANumb - 2
ReDim EPAList(EPANumb)
For PrjCnt = 0 To EPANumb
If EPANumb > 0 Then
EPAList(PrjCnt) = "'" & Worksheets("Instructions").Cells((PrjCnt + 2), 2).Value & "'"
Else
EPAList(PrjCnt) = Worksheets("Instructions").Cells((PrjCnt + 2), 2).Value
End If
Next
PrjList = Join(EPAList, ",")
'Open IE and navigate to URL
Set IE = New InternetExplorerMedium
IE.Visible = True 'only if you want to see what is happening
URL = "http://anysite/SnakeEyes/grid.html"
IE.navigate URL
'need If statement in case user needs to do sign on.
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While IE.Busy = True Or IE.ReadyState <> 4: DoEvents: Loop
Application.Wait (Now + TimeValue("0:00:05"))
'Webpage Loaded
Application.StatusBar = URL & " loaded"
Set oHtml = IE.document
'HWNDScr = IE.HWND
'SetForegroundWindow HWNDScr
'Open search box and reset search parameters
oHtml.getElementById("search_grid_c_top").Click
'IE.Document.getElementById("fbox_grid_c_reset").Click
Set objEvent = oHtml.createEvent("HTMLEvents")
objEvent.initEvent "change", True, False ' **** NEW ****
Set HTMLtags = oHtml.getElementsByTagName("select")
For i = 0 To HTMLtags.Length - 1
If HTMLtags(i).className = "selectopts" Then
If EPANumb > 0 Then
HTMLtags(i).Value = "in"
Else
HTMLtags(i).Value = "eq"
End If
' HTMLtags.dispatchEvent objEvent ' **** NEW ****
Exit For
End If
Next i
Set objEvent = oHtml.createEvent("HTMLEvents")
objEvent.initEvent "change", True, False ' **** NEW ****
Set HTMLtags = oHtml.getElementsByTagName("input")
For i = 1 To HTMLtags.Length - 1
If HTMLtags(i).ID > "jqg" And HTMLtags(i).ID < "jqh" Then
HTMLtags(i).Focus
HTMLtags(i).Value = PrjList
Exit For
End If
Next i
HTMLtags(i).dispatchEvent objEvent ' **** NEW ****
'HTMLtags(i).FireEvent objEvent ' **** NEW **** DispatchEvent gives an error 438.
'FireEvent gives an error 5 if using the (i); error 438 without it.
HTML Code
Will the "change" event trigger the update for both without VBA in IE? If the "change" event is only associated with the input box and will not trigger update for dropdown list without VBA, then I think it won't work with VBA either. Besides, what the "change" event is like?
I make a demo like below and it seems that the "change" event can be triggered well, you could try to check it.
HTML code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<table>
<tbody>
<tr>
<td class="operators">
<select class="selectopts">
<option value="eq">equal</option>
<option value="in">is in</option>
<option value="ni">is not in</option>
</select>
</td>
<td class="data">
<input class="input-elm" id="jqg1" role="textbox" type="text" size="10" value="'1006191'"/>
</td>
</tr>
</tbody>
</table>
<script>
var select = document.getElementsByClassName('selectopts')(0);
var input = document.getElementById('jqg1');
input.addEventListener('change', updateValue);
function updateValue() {
select.value = "in";
}
</script>
</body>
</html>
VBA code:
Sub LOADIE()
Set ieA = CreateObject("InternetExplorer.Application")
ieA.Visible = True
ieA.navigate "http://somewebsite"
Do Until ieA.readyState = 4
DoEvents
Loop
Set doc = ieA.Document
Set Search = doc.getElementByID("jqg1")
Search.Value = "VBA"
Dim event_onChange As Object
Set event_onChange = ieA.Document.createEvent("HTMLEvents")
event_onChange.initEvent "change", True, False
Search.dispatchEvent event_onChange
'ieA.Quit
'Set ieA = Nothing
End Sub

Retrieve the value of a read-only input text box using VBScript

I'm working with an Internet Explorer based application where I need to retrieve the value of an input text box that is read only. I've looked at other Stack Overflow questions and don't see anything about getting the value of a read only or hidden input box. I haven't found anything I can use on the internet either.
Here's the HTML code for the input box I'm trying to get the value from:
<div class="col-xs-10 col-sm-9 col-md-6 col-lg-5 form-field input_controls">
<div class="hidden" ng-non-bindable="">
<input name="sys_original.x_opt_im_issue_task.number" id="sys_original.x_opt_im_issue_task.number" type="hidden" value="TSK0111065" />
</div>
<input class="form-control disabled " id="sys_readonly.x_opt_im_issue_task.number" readonly="readonly" ng-non-bindable="" value="TSK0111065" />
</div>
Here's the VBScript code I'm trying to use to get the value of the input text box that isn't working:
UPDATED
Option Explicit
Dim WShell, objShell, objIE
Dim strMessage, URL, ErrMsg, URLFound, Browser
Dim EN_ID, EntNowID
Sub Main()
On Error Resume Next
Set WShell = CreateObject("WScript.Shell")
Set objShell = CreateObject("Shell.Application")
If Err.Number <> 0 Then ShowError("Failed to create objects")
On Error GoTo 0
Check_EN
SetEverythingToNothing
End Sub
'---------------------------------
Sub ShowError(strMessage)
MsgBox strMessage & vbNewline & vbNewline & "Error number: " & Err.Number & vbNewline & "Source: " & Err.Source & vbNewline & "Description: " & Err.Description
Err.Clear
SetEverythingToNothing
End Sub
'------------------------------
Sub Check_EN()
URL = "https://enterprisenow.mysite.com"
ErrMsg = "EnterpriseNOW is not open or on the incorrect page. Please check & rerun the macro."
Check_URL
ErrMsg = ""
Set EN_ID = objIE.document.getElementById("sys_readonly.x_opt_im_issue_task.number")
EntNowID = EN_ID.Value
MsgBox EntNowID
End Sub
'------------------------------
Function Check_URL()
URLFound = False
For Each Browser In objShell.Windows()
If InStr(UCase(Browser.LocationURL), UCase(URL)) > 0 Then
If InStr(UCase(Browser.FullName), "IEXPLORE.EXE") Then
If Err.Number = 0 Then
Set objIE = Browser
URLFound = True
Exit For
End If
End If
End If
Next
If URLFound = False Then
MsgBox "Unable to find URL."
SetEverythingToNothing
End If
End Function
'-----------------------------
Sub SetEverythingToNothing()
Set WShell = Nothing
Set objShell = Nothing
Set Browser = Nothing
Set objIE = Nothing
End Sub
I'm able to set the objIE object and find the URL, but I'm receiving "Run-time error '424': Object required". Is it because the input text box is hidden or read only? I'm also wondering if it has anything to do with nested div tags?
Try the following - it worked for me. What I noticed is that if I accessed:
objIE.document.getElementById("sys_readonly.x_opt_im_issue_task.number").Value
more than once, I got the error: Object required
However if I used 'Set' and created an object like so:
Set tasknumber = objIE.document.getElementById("sys_readonly.x_opt_im_issue_task.number")
I could then access the value multiple times without receiving the error.
Option Explicit
Dim objShell : Set objShell = CreateObject("shell.application")
Dim URL : URL = "https://enterprisenow.mysite.com/"
Dim URLFound : URLFound = False
Dim Browser, tasknumber, tasknumbervalue
For Each Browser In objShell.Windows()
If InStr(UCase(Browser.FullName), "IEXPLORE.EXE") Then
If InStr(UCase(Browser.LocationURL), UCase(URL)) > 0 Then
If Err.Number = 0 Then
Set tasknumber = Browser.document.getElementById("sys_readonly.x_opt_im_issue_task.number")
If (NOT IsNull(tasknumber) And NOT tasknumber Is Nothing) Then
tasknumbervalue = tasknumber.value
End If
Set tasknumber = Nothing
Exit For
End If
End If
End If
Next
MsgBox tasknumbervalue
Set Browser = Nothing
Set objShell = Nothing
Well, it's not the solution I was hoping for, but it's easier than trying to get the number from the input field.
I had a feeling that the iframe tag may be preventing me from detecting the input field ID, so I looked at the iframe and saw that the TSK number in the input field was also in the iframe tag.
Instead of trying this:
EN_ID = objIE.document.getElementById("sys_readonly.x_opt_im_issue_task.number").Value
I was able to use this:
iframeName = Split(objIE.document.getElementById("gsft_main").Title, " | ") 'Title = "TSK0111065 | Issue Task | ServiceNow"
EN_ID = iframeName(0)

How to get the title of a website page in VBA?

Here is a piece of code I have been working on to print the title of a window.
Dim my_title2 as Variant
Set objShell = CreateObject("Shell.Application")
IE_count = objShell.Windows.Count
MsgBox ("The number of pages is: " & IE_count)
For x = 0 To (IE_count - 1)
On Error Resume Next
my_url = objShell.Windows(x).document.Location
my_title = objShell.Windows(x).document.Title
If my_title Like "F-Engine" & "*" Then
Set ie = objShell.Windows(x)
my_title2 = ie.document.Title
'my_title2 = objShell.Windows(x).document.Title
MsgBox ("The wanted title for the page should corrrespond. " & my_title2)
Exit For
Else
End If
Next
I am having trouble printing the title of the window after Set ie = objShell.Windows(x).
When y_title2 = ie.document.title, the MsgBox displays:
"The wanted title for the page should correspond."
It prints nothing after this sentence. So the title assigned to "ie" is not being displayed.
If my_title2 = objShell.Windows(x).document.title, the MsgBox displays:
"The wanted title for the page should correspond. F-Engine"
Why am I not able to print the title of the page with the first declaration of my_title2?
I am doing this to verify if the page is being correctly picked up after a title "F-Engine" is found. To do so, I am trying to print the value of the title of the Internet Explorer window. It seems like nothing has been set and passed.
Not every object in objShell.Windows represents an IE page/tab - they might be instances of Windows Explorer. In those cases there is no document property to access.
You can test for this instead of using On Error Resume Next:
Dim w As Object, myUrl, myTitle, ie
For Each w In CreateObject("Shell.Application").Windows
If w.Name = "Internet Explorer" Then
myUrl = w.document.Location
myTitle = w.document.Title
Debug.Print myUrl, myTitle
If myTitle Like "F-Engine*" Then
Set ie = w
Debug.Print "Found: " & myTitle
Exit For
End If
End If
Next w

VBScript to recursively scrape a local intranet page for links

I've been tasked with identifying all of the many links we have on our team's intranet. The goal is to declutter (find duplicate links or dead links).
I wrote this script that will go to our page and scrape every link while identifying the file extension. What I'm not sure how to do is to make this recursive. Once it goes to our site and scrapes those links, if it finds another URL (such as htm or html) I want it to follow THAT link and scrape the same from there and continue on until every link associated with the initial URL is exhausted. I'd like it to create a type of hierarchy in the csv such as (example headers):
lvl0_Link_Title,lvl0_File_Type,lvl0_URL,lvl1_Link_Title,lvl1_File_Type,lvl1_URL,lvl2_Link_Title,lvl2_File_Type,lvl2_URL,lvl3_Link...etc.
Obviously, this would end up with a pretty massive csv. If there is a better/cleaner method to achieve the same, I'm open to it.
Set objWshShell = Wscript.CreateObject("Wscript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set IE = CreateObject("internetexplorer.application")
on error resume next
filename = fso.GetParentFolderName(WScript.ScriptFullName) & "\URL_Dump_Oldsite.csv"
'==============================================
'Create headers for CSV
set output = fso.opentextfile(filename,2,true)
output.writeline "Link Title,File Type,URL"
output.close
'==============================================
IE.Visible = false
IE.Navigate "URL OF OUR INTRANET"
Do While IE.Busy or IE.ReadyState <> 4: WScript.sleep 100: Loop
Do Until IE.Document.ReadyState = "complete": WScript.sleep 100: Loop
for each url in ie.document.getelementsbytagname("a")
if not url.href is nothing then
ext = mid(url.href,instrrev(url.href,"."))
set output = fso.opentextfile(filename,8,true)
output.writeline replace(url.innertext,","," / ") & "," & ext & ",=HYPERLINK(" & chr(34) & url.href & chr(34) & ")"
output.close
end if
next
'===========================================
'Keyword filter for removal
Dim arrFilter
arrFilter = Array("bakpcweb", _
"aims", _
"element", _
"objid", _
"nodeid", _
"objaction", _
"javascript", _
"itemtype")
'===========================================
'Delete lines from csv file containing keywords
strFile1 = fso.GetParentFolderName(WScript.ScriptFullName) & "\URL_Dump_Oldsite.csv"
Set objFile1 = fso.OpenTextFile(strFile1)
Do Until objFile1.AtEndOfStream
i = 0
strLine1 = trim(lcase(objFile1.Readline))
for a = lbound(arrFilter) to ubound(arrFilter)
if instr(strLine1,arrFilter(a)) <> 0 then
i = i + 1
End If
next
if i = 0 then
strNewContents1 = strNewContents1 & strLine1 & vbCrLf
end if
Loop
objFile1.Close
Set objFile1 = fso.OpenTextFile(strFile1,2,true)
objFile1.Write strNewContents1
objFile1.Close
'===========================================
'Delete blank lines from csv file
strFile = fso.GetParentFolderName(WScript.ScriptFullName) & "\URL_Dump_Oldsite.csv"
Set objFile = fso.OpenTextFile(strFile)
Do Until objFile.AtEndOfStream
strLine = objFile.Readline
strLine = Trim(strLine)
If Len(strLine) > 0 Then
strNewContents = strNewContents & strLine & vbCrLf
End If
Loop
objFile.Close
Set objFile = fso.OpenTextFile(strFile,2,true)
objFile.Write strNewContents
objFile.Close
'===========================================
'Remove duplicate lines from csv file
Set objDictionary = CreateObject("Scripting.Dictionary")
strFile = fso.GetParentFolderName(WScript.ScriptFullName) & "\URL_Dump_Oldsite.csv"
Set objFile = fso.OpenTextFile(strFile)
Do Until objFile.AtEndOfStream
strLine = objFile.Readline
strLine = Trim(strLine)
If Not objDictionary.Exists(strLine) Then
objDictionary.Add strLine, strLine
End If
Loop
objFile.Close
Set objFile = fso.opentextfile(strFile,2,true)
For Each strKey in objDictionary.Keys
objFile.WriteLine strKey
Next
objFile.Close
objDictionary.clearall
'===========================================
wscript.echo "Done!"
ie.quit
wscript.quit
Thank you!
This might not be the answer you were expecting, but it sounds like you're reinventing the wheel here, and with a sub-standard tool. In my experience, I also wouldn't find the lvl0, lvl1 etc. format particularly useful when reporting later.
I would strongly recommend you instead use an existing program to scan your intranet, such as Xenu or for a more in-depth analysis, try Screaming Frog SEO Spider (free version is limited to about 500 pages, as I recall, but you can give it a try). These tools have features to save reports, which should suit your needs.
If that doesn't work for you, please comment or edit your answer to explain why you must do this yourself and report in the specified format.
Edit: Here's an example screenshot from the free Xenu program, which lists every resource it tried, its status, links in/out, and type, which can assist with your requirement to report on filetypes. It will also generate full HTML reports if you want stats.

write lines to file and when there 5 lines in needs to execute a statement vbscript

here is a code which i wanne run on background so no windowmessages. The meaning of it is that it checks a connection. If there isn't a connection it writes a error to a file. a function reads that file if there are 5 lines it should create a event-error. The problem is that the last part doesn't work correctly.
my qeustion is can somebody fix it or help me fixing it. Here is the code:
strDirectory = "Z:\text2"
strFile = "\foutmelding.txt"
strText = "De connectie is verbroken"
strWebsite = "www.helmichbeens.com"
If PingSite(strWebsite) Then WScript.Quit 'Website is pingable - no further action required
Set objFSO = CreateObject("Scripting.FileSystemObject")
RecordSingleEvent
If EventCount >= 5 Then
objFSO.DeleteFile strDirectory & strFile
Set WshShell = WScript.CreateObject("WScript.Shell")
strCommand = "eventcreate /T Error /ID 100 /L Scripts /D " & _
Chr(34) & "Test event." & Chr(34)
WshShell.Run strcommand
End if
'------------------------------------
'Record a single event in a text file
'------------------------------------
Sub RecordSingleEvent
If Not objFSO.FolderExists(strDirectory) Then objFSO.CreateFolder(strDirectory)
Set objTextFile = objFSO.OpenTextFile(strDirectory & strFile, 8, True)
objTextFile.WriteLine(Now & strText)
objTextFile.Close
End sub
'----------------
'Ping my web site
'----------------
Function PingSite( myWebsite )
Set objHTTP = CreateObject( "WinHttp.WinHttpRequest.5.1" )
objHTTP.Open "GET", "http://" & myWebsite & "/", False
objHTTP.SetRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MyApp 1.0; Windows NT 5.1)"
On Error Resume Next
objHTTP.Send
PingSite = (objHTTP.Status = 200)
On Error Goto 0
End Function
'-----------------------------------------------
'Counts the number of lines inside the text file
'-----------------------------------------------
Function EventCount()
strData = objFSO.OpenTextFile(strDirectory & strFile,ForReading).ReadAll
arrLines = Split(strData,vbCrLf)
EventCount = UBound(arrLines)
Set objFSO = Nothing
End Function
thats the code you can copy it to see it your self. i thank you for your time and intrest
Greets helmich
It doesn't work because function EventCount sets objFSO=nothing, so,
If EventCount >= 5 Then
objFSO.DeleteFile strDirectory & strFile
fails
Use the logevent method of the Shell object
If EventCount >= 5 Then
objFSO.DeleteFile strDirectory & strFile
Set WshShell = WScript.CreateObject("WScript.Shell")
Call WshShell.LogEvent(1, "Test Event")
End if
You don't need to run a separate command
Thats not the problem is this
Windows host script gives a error
Line:41
Char:2
Translation of error: the data required for this operation are not yet available
code: 80070057
source: WinHttp.WinHttpRequest
thats the problem and i do not know how to fix it
it has something to do that he can't read the lines in the txtfile and then not execute the create event command