I have programmed a post image HTA which is launched after an XP image has been loaded onto a computer. The HTA gathers information from the user (ie primary user name, department, etc) and updates the registry under a custom key. Management has asked if I can pull the computer's warranty information (specifically the warranty end date) from the vendor's website (in this case Lenovo) and update the registry with this info. Lenovo allows anonymous lookup using computer type and serial number and returns a page showing warranty information. Is there a way using vbscript (or maybe javascript?) to parse the returned page for the data I'm looking for?
Thanks in advance,
Gill
Using an HTML parser would probably be a more robust way to do this, but it's easy with VBScript to just script Internet Explorer through OLE Automation.
Dim ie, frm
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.Navigate "http://www-307.ibm.com/pc/support/site.wss/" & _
"document.do?lndocid=LOOK-WARNTY#sw"
Do Until ie.ReadyState = 4 '' READYSTATE_COMPLETE
WScript.Sleep 100
Loop
Set frm = ie.Document.Forms.warrantyLookup
frm.type.Value = "2644"
frm.serial.Value = "23AB123"
frm.Submit
Do Until ie.Document.ReadyState = "complete"
WScript.Sleep 100
Loop
'' Locate the information you want to scrape from the
'' ie.Document DOM at this point
ie.Quit
You can scrape the page that is returned fairly easily, all it really takes is an HTML parser, and then knowledge of where the information you want is located within the returned page. I do not know of any VBScript HTML parsers, but I am sure they exist. If you cannot find one, however, you can call out to an external program from locally running code, so you could write a page scraping utility in any number of languages (or use some sort of grep utility), and that may do what you are looking for.
Related
I have a frontend Microsoft Access .mde database that connects to two backends simultaneously. I also give the user the option to link to a sandbox mode backend that resides on their local computer. While I'm developing the frontend, I stay linked to my local version of the sandbox so that I don't mess with the two backends. Sometimes, I want to reset my sandbox to match the data in the backends. The sandbox is a little different in that I combine the two backends together into one. (One of the backends is just log data, so I delete that data after it's in my new sandbox.) I have the process of copying the files and data fairly automated through VBA.
I want to also automate setting the permissions on the new sandbox file after it is copied. The sandbox file should have much more lenient permissions since its data really doesn't matter. I keep getting the error "Object not set." after trying to obtain the Tables collection in VBA in the sandbox file from my developer frontend. I have deduced that I am able to see the Containers and corresponding Documents in the frontend developer file, but I am not able to see them from the frontend developer file when I try to access them programmatically.
I'm assuming that this must be some built-in security feature of Access. Perhaps Microsoft doesn't want to allow a file to modify the security of a different file. Here is some of my code to help you see what I'm doing.
All of these databases utilize the same user-level security .mdw file residing on the server. The database was originally created in Access 2000, but I have since upgraded to Access 2010. However, the I maintain the original Access 2000 file format to be able to utilize the built-in multi-user security.
Public Function CorrectSandbox()
Dim appBackend As Application
Dim appLog As Application
Dim appSandbox As Application
Dim tdf As TableDef
Dim i As Long
Dim doc As DAO.Document
Dim ctr As DAO.Container
'copy the files
mFile.DeleteFile LOCAL_SANDBOX_PATH
mFile.CopyFile PRODUCTION_PATH, LOCAL_SANDBOX_PATH
'copy the log tables
Set appSandbox = OpenSandbox()
Set appLog = OpenLog()
For Each tdf In appLog.CurrentDb().TableDefs
If Left$(tdf.Name, 1) = "_" Then
appSandbox.DoCmd.TransferDatabase acImport, "Microsoft Access", GetAdminPath(eLive), acTable, tdf.Name, tdf.Name, True
'Set permissions for the object accordingly
Set ctr = appSandbox.CurrentDb().Containers!Tables
Set doc = ctr.Documents(tdf.Name) '*** ERROR: Object not set
doc.UserName = "User"
doc.Permissions = 852222
End If
Next tdf
appLog.Quit
appSandbox.Quit
End Function
I am trying to develop a simple tool in VB.NET that, within a loop, navigates to a website and save the page as an HTML document.
I can set up the loop easily as the pages are numbered sequentially.
www.example.com/pages/1.html
www.example.com/pages/2.html
www.example.com/pages/3.html
www.example.com/pages/4.html
Where I am having trouble is with finding a method to save the actual page. I was going to utilize a series of SendKeys to Alt, File, Saves As, Enter, etc.. but I figured there had to be some sort of object/method that could be used to do this more straight forward.
I've enabled the COM Internet Controls Reference and declared and new SHDoc.Vw.InternetExplorer and am able to programatically open the browser in a new window and navigate to the desired page(s). I've search online for a solution to the Save issue but have been unsuccessful. Does anyone have any ideas?
Dim baseUrl As String = "http://www.example.com/pages/{0}.html"
Dim basePath As String = "C:\some\path{0}.html"
Using ws As New System.Net.WebClient()
ForEach i As Integer In Enumerable.Range(1,4)
wc.DownloadFile(String.Format(baseUrl, i), string.Format(basePath, i))
Next i
End Using
If you have a lot of these want to get a little fancy, you can even use the DownloadFileAsync() method to queue up several of thses at once.
I'm trying to input some code that hides "Design View" as an option for our internal application unless a certain permission requirement is met.
The following code works with one exception:
On Error Resume Next
If Not GetUserInfo("ADMIN_PERMIS") = 1 Then
Dim cb As CommandBar
Dim cbCtl As CommandBarControl
For Each cb In CommandBars
If cb.type = msoBarTypePopup Then
For Each cbCtl In cb.Controls
If cbCtl.Caption = "&Design View" Then
cbCtl.enabled = True
cbCtl.visible = False
Else
cbCtl.visible = True
End If
Next
End If
Next
Set cb = Nothing: Set cbCtl = Nothing
End If
The one problem with this is that it disables Design View not only for the current database, but also for any other access database that is launched. I'm looking for a way to try and apply this code in such a way that it only affects the Access database I have the code in and not in every single instance of it.
I recommend converting the database into a compiled, executable only .accde file (File --> Save & Publish --> Make ACCDE). Doing this will prevent any design or code changes in the application. Keep a development version in the normal .accdb format. Make your changes there and then compile into the .accde version for each update.
Since your team updates the database often, you could benefit from using Peter De Baets' database starter. The database starter makes a local copy of the front end of the database, allowing uses to continue to work while design changes are being made. After the production accde front end file is updated, the users will automatically copy the new file the next time they open the database. In my office I have found that I can push out a quick fix and simply email everyone saying "Close and reopen the database guys!".
All these answers are great. If you are interested in the simplest method, I found the form holds the key, albeit in a strange spot.
In the forms properties->Other Tab->Shortcut Menu =No
Our MS Access 2000 developer left the company a year ago. We need to open his app in design mode in order to make modifications. Double-clicking the .mdb file while holding the shift key doesn't work. When I do that the developer toolbar shows for a split second, then all toolbars go away and the app opens as users would see it. No toolbars show and only a basic dashboard is visible to run the app. I tried using the password recovery tool mentioned here but the tool says there is no password. Can someone tell me how I can open this app to make code modifications?
Beth's answer worked for myself and a co-worker. I've copied the solution here from the link in case the link dies.
"...To unlock the Access DB you can use the following if you know the full path to your database.
Copy the following function into a module in ANOTHER database and call the function. You will need to set the strPath to the path of your database."
Public Function ResetExternalDatabaseBypassKey _
(Optional tfAllow As Boolean = True)
'Name: ResetExternalDatabaseBypassKey (Function)
'Purpose: Sets AllowByPassKey to true in another Access Database
'Author: John Spencer UMBC-CHPDM
'Date: May 02, 2000, 12:08:19 PM
'*******************************************
Dim dbs As Database
Dim strPath As String
On Error GoTo ResetExternalDatabaseBypassKey_ERROR
strPath = "C:/MyDatabases/SomeDataBaseName.mdb"
Set dbs = DBEngine.Workspaces(0).OpenDatabase(strPath)
dbs.Properties("AllowByPassKey") = tfAllow
ResetExternalDatabaseBypassKey_ERROR:
Select Case Err.Number
Case 3270 'Property not found
MsgBox "Allow Bypass Key property does not exist " & _
"for the chosen database."
Case Else
MsgBox Err.Number & ": " & Err.Description
End Select
End Function
Make sure there wasn't another copy left around without this code enabled.
This is typical code used to do this sort of thing, SetByPass There are instructions to hit Cntl-G to open VBA Editor and run code to unset this thing.
Have you tried creating a new blank database, and then importing everything?
It sounds like the shift key by-pass has been set, but that's as noted usually only needed for deployment. In fact, for any access developer, this is quite much a standard approach.
So, it not clear if anything at all been locked up here or the person just set things up as most access applications should be when deployed to users.
About the only thing you lose when importing to another application is the tools startup settings and the shift key. If there are custom menus, make sure you check the option to import those also. (However, be careful, as sometimes custom menus can be setup to run a macro on startup, and this was an old security trick). So, if importing once with tool bars and holding down shift key still causes startup code to run, then try creating another blank database and this time import everything except the menu+tools bars from the old application. Holding down shift key will thus then work for you.
Also, if the system not asking your for a password, then what would you expect a password recovery program to do? All you need is basic access developer skills here to deal with this problem and throwing things like password removal when you not being prompted for passwords will not move you forward here.
On the other hand, if after importing all the forms into a new database the design ability is grayed out, then this was in fact a mde file, and you are in a rather difficult situation unless you can find the original mdb file used to create the mde.
I'm trying to open a series of Excel spreadsheets using an instance of Excel created inside of a module in an Access database. I can get the files to open properly; however, the actual call to make Excel start takes quite a while, and to open the files takes even longer. The location of the files doesn't matter (same time to open on a local HDD as a network drive).
In an attempt to figure out what was taking so long, I added a timer to the logging module. Opening the files takes approximately 2m30s, during which the host application (Access) is entirely unresponsive to user input); the rest of the script executes in less than 10 seconds.
I'm using the standard Excel.Workbooks.Open call as follows
Set OpenSpreadsheet = Excel.Workbooks.Open(Name, 2, False)
Using Debug.Print methods around this line says it can take up to 2 1/2 minutes for this one line to execute.
Is there anything I can do to make the Excel files open quicker?
EDIT: When opening, UpdateLinks is False and ReadOnly is True; all other options are left to their defaults.
First idea: Can you use a jet driver with an ODBC connection to Excel, instead of opening it in an Excel object? Might be much faster.
Second idea: Make sure to create and instantiate the Excel application object just once at the beginning of the routine, then use the Excel.Workbooks.Open() and Excel.ActiveWorkbook.Close() for each spreadsheet. That way you're not "re-launching" the MS Excel application each time.
To draw out the second of #BradC's well-advised recommendations, if you need to use Excel in more than one procedure, create a self-initializing global function. I always use late binding for automating Office apps.
Public Function Excel(Optional bolCleanup As Boolean = False) As Object
Static objExcel As Object
If bolCleanup Then
If Not objExcel Is Nothing Then
Set objExcel = Nothing
Exit Function
End If
End If
If objExcel Is Nothing Then
Set objExcel = CreateObject("Excel.Application")
End If
Set Excel = objExcel
End Function
Then you can use it in code without needing to initialize it, and the single instance will remain available to any code that needs to use Excel.
And when you shut down your app, you'd call Excel(True) to clean up.
I do this with Outlook and Word all the time. However, there are some COM apps that it works poorly with, such as PDF Creator, which doesn't take kindly to this kind of treatment (you end up in an endless loop with it shutting down and re-initializing itself if you try to destroy the instance this way).
Another approach depends on your setup and process.
In my case I need read-only access to a set of Excel documents stored on SharePoint. My code is currently like:
For each path in paths
set wb = Workbooks.open(path,false)
next
In this case, each workbook is individually downloaded each time a workbook is opened. It would be significantly more efficient if the files were downloaded asyncronously and after the download is complete, the rest of the process executes on the local disk.
My idea is to use CopyFileEx() and pass a callback function. Excel will then download the Excel documents to disk asynchronously and call a VBA function regarding progress. When all files are completed, we can launch the next part of the process, which opens the local workbooks, scans them and then removes them from the local drive.
I'll post code later if I manage to implement it.