How to run VBScript GetObject while the computer is locked? - excel

For a few reasons discussed here I can't open an excel worksheet like this:
Set excel = CreateObject("Excel.Application")
Set workbook = excel.Workbooks.Open(file_path.xls)
excel.Visible = True
So I'm trying to open it like this:
CreateObject("WScript.Shell").Run "excel.exe"
WScript.Sleep 5000
CreateObject("WScript.Shell").Run "excel.exe"
WScript.Sleep 5000
Set excel = GetObject(,"Excel.Application")
Set workbook = excel.Workbooks.Open( excel_file_path, 3)
excel.Visible = True
This runs just fine when my computer isn't locked. And usually VBScripts can run even when a computer is locked. However, only when the computer is locked, at the line GetObject(,"Excel.Application") I get the following runtime error:
Error: ActiveX component can't create object: 'GetObject'
Code: 800A01AD
Source: Microsoft VBScript runtime error
I tried changing my Windows 7 settings to never lock after some inactivity, but my company's IT department has enforced that setting.
Is there a way to run this script from a locked screen, or is there an alternative you recommend?
Edit:
It has something to do with the way the excel file is being opened... If I open a new blank excel page than lock the screen, GetObject will work just fine getting that document, but if I open it using the shell then log out, it won't...

In the section that does not seem to work, add this line after setting visible = TRUE, and see if your calculations then work as expected:
CreateObject("WScript.Shell").AppActivate objExcel.Name
Not sure if it will work, but I am doing similar things in some code and this is what's there.
I must have copied or read about it somewhere (wish I could give credit to where).
FYI - I have a vbscript that opens Excel, starts a new workbook, reads a file in as text via a querytable object, then does some automated edits. The code that works for me is:
...
set objExcel = CreateObject("Excel.application")
' Commented out the following line, so the user can see something is happening.
' objExcel.application.screenupdating = false ' Don't update the screen while shucking and jiving is going on.
objExcel.visible = true
objExcel.application.cursor = 2 ' change cursor to the hourglass.
CreateObject("WScript.Shell").AppActivate objExcel.Name
' Create a new workbook and worksheet
objExcel.workbooks.add
objExcel.worksheets.add
etc

Try the code:
CreateObject("WScript.Shell").Run "excel.exe """ & excel_file_path & """"
WScript.Sleep 5000
CreateObject("WScript.Shell").Run "excel.exe"
WScript.Sleep 5000
Set excel = GetObject(,"Excel.Application")

Related

How do I get my macro to run automatically every Tuesday at 1:20pm? [duplicate]

I have a xlsx macro enabled file . How can I set it in the task manager so that everyday at 9 AM task manager would open the workbook, fire the macro and close the workbook.
So far i am using
Application.OnTime . . .
But i realize that keeping the xlsm file open is inconvenient
Better to use a vbs as you indicated
Create a simple vbs, which is a text file with a .vbs extension (see sample code below)
Use the Task Scheduler to run the vbs
Use the vbs to open the workbook at the scheduled time and then either:
use the Private Sub Workbook_Open() event in the ThisWorkbook module to run code when the file is opened
more robustly (as macros may be disabled on open), use Application.Run in the vbs to run the macro
See this example of the later approach at Running Excel on Windows Task Scheduler
sample vbs
Dim ObjExcel, ObjWB
Set ObjExcel = CreateObject("excel.application")
'vbs opens a file specified by the path below
Set ObjWB = ObjExcel.Workbooks.Open("C:\temp\rod.xlsm")
'either use the Workbook Open event (if macros are enabled), or Application.Run
ObjWB.Close False
ObjExcel.Quit
Set ObjExcel = Nothing
Three important steps - How to Task Schedule an excel.xls(m) file
simply:
make sure the .vbs file is correct
set the Action tab correctly in Task Scheduler
don't turn on "Run whether user is logged on or not"
IN MORE DETAIL...
Here is an example .vbs file:
`
' a .vbs file is just a text file containing visual basic code that has the extension renamed from .txt to .vbs
'Write Excel.xls Sheet's full path here
strPath = "C:\RodsData.xlsm"
'Write the macro name - could try including module name
strMacro = "Update" ' "Sheet1.Macro2"
'Create an Excel instance and set visibility of the instance
Set objApp = CreateObject("Excel.Application")
objApp.Visible = True ' or False
'Open workbook; Run Macro; Save Workbook with changes; Close; Quit Excel
Set wbToRun = objApp.Workbooks.Open(strPath)
objApp.Run strMacro ' wbToRun.Name & "!" & strMacro
wbToRun.Save
wbToRun.Close
objApp.Quit
'Leaves an onscreen message!
MsgBox strPath & " " & strMacro & " macro and .vbs successfully completed!", vbInformation
'
`
In the Action tab (Task Scheduler):
set Program/script: = C:\Windows\System32\cscript.exe
set Add arguments (optional): = C:\MyVbsFile.vbs
Finally, don't turn on "Run whether user is logged on or not".
That should work.
Let me know!
Rod Bowen
I referred a blog by Kim for doing this and its working fine for me. See the blog
The automated execution of macro can be accomplished with the help of a VB Script file which is being invoked by Windows Task Scheduler at specified times.
Remember to replace 'YourWorkbook' with the name of the workbook you want to open and replace 'YourMacro' with the name of the macro you want to run.
See the VB Script File (just named it RunExcel.VBS):
' Create a WshShell to get the current directory
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")
' Create an Excel instance
Dim myExcelWorker
Set myExcelWorker = CreateObject("Excel.Application")
' Disable Excel UI elements
myExcelWorker.DisplayAlerts = False
myExcelWorker.AskToUpdateLinks = False
myExcelWorker.AlertBeforeOverwriting = False
myExcelWorker.FeatureInstall = msoFeatureInstallNone
' Tell Excel what the current working directory is
' (otherwise it can't find the files)
Dim strSaveDefaultPath
Dim strPath
strSaveDefaultPath = myExcelWorker.DefaultFilePath
strPath = WshShell.CurrentDirectory
myExcelWorker.DefaultFilePath = strPath
' Open the Workbook specified on the command-line
Dim oWorkBook
Dim strWorkerWB
strWorkerWB = strPath & "\YourWorkbook.xls"
Set oWorkBook = myExcelWorker.Workbooks.Open(strWorkerWB)
' Build the macro name with the full path to the workbook
Dim strMacroName
strMacroName = "'" & strPath & "\YourWorkbook" & "!Sheet1.YourMacro"
on error resume next
' Run the calculation macro
myExcelWorker.Run strMacroName
if err.number <> 0 Then
' Error occurred - just close it down.
End If
err.clear
on error goto 0
oWorkBook.Save
myExcelWorker.DefaultFilePath = strSaveDefaultPath
' Clean up and shut down
Set oWorkBook = Nothing
' Don’t Quit() Excel if there are other Excel instances
' running, Quit() will shut those down also
if myExcelWorker.Workbooks.Count = 0 Then
myExcelWorker.Quit
End If
Set myExcelWorker = Nothing
Set WshShell = Nothing
You can test this VB Script from command prompt:
>> cscript.exe RunExcel.VBS
Once you have the VB Script file and workbook tested so that it does what you want, you can then use Microsoft Task Scheduler (Control Panel-> Administrative Tools--> Task Scheduler) to execute ‘cscript.exe RunExcel.vbs’ automatically for you.
Please note the path of the macro should be in correct format and inside single quotes like:
strMacroName = "'" & strPath & "\YourWorkBook.xlsm'" &
"!ModuleName.MacroName"
Code below copied from -> Here
First off, you must save your work book as a macro enabled work book. So it would need to be xlsm not an xlsx. Otherwise, excel will disable the macro's due to not being macro enabled.
Set your vbscript (C:\excel\tester.vbs). The example sub "test()" must be located in your modules on the excel document.
dim eApp
set eApp = GetObject("C:\excel\tester.xlsm")
eApp.Application.Run "tester.xlsm!test"
set eApp = nothing
Then set your Schedule, give it a name, and a username/password for offline access.
Then you have to set your actions and triggers.
Set your schedule(trigger)
Action, set your vbscript to open with Cscript.exe so that it will be executed in the background and not get hung up by any error handling that vbcript has enabled.
I found a much easier way and I hope it works for you. (using Windows 10 and Excel 2016)
Create a new module and enter the following code:
Sub auto_open()
'Macro to be run (doesn't have to be in this module, just in this workbook
End Sub
Set up a task through the Task Scheduler and set the "program to be run as" Excel (found mine at C:\Program Files (x86)\Microsoft Office\root\Office16). Then set the "Add arguments (optional): as the file path to the macro-enabled workbook. Remember that both the path to Excel and the path to the workbook should be in double quotes.
*See example from Rich, edited by Community, for an image of the windows scheduler screen.

Calling Workbooks.Open

This VBScript errs as "unknown runtime error", on the VBScript line that calls the application object's RUN method, which I'm quite sure I'm using correctly, syntactically.
With only one workbook open under the application object, I probably don't even need to prefix it with the Workbookname.
It appears the previous line (which sets the wb variable to the application object's Workbooks.Open method, does not open. Nor does it err, nor does it "eventually" open. The path is correct, the filename is correct, there is no On Error Resume Next in my VBScript.
How can the workbook not open and not error?
I hope I am wrong in thinking there is a "wait/pause" issue. Acting directly on the Excel object model, it seems like the VBScript code waiting until the excelapp object has opened the workbook should be a given?
dim excelapp, wb
set excelapp = createobject("excel.application")
excelapp.enableevents=true
excelapp.visible=true
set wb = excelapp.workbooks.open("C:\Users\John\Desktop\Scheduled Jobs from Isaac\Availability.xlsb")
'MSGBOX "SHOULD BE OPEN"
excelapp.windowstate = -4137 'value for constant xlMaximized acccording to msdn
excelapp.caption = "Running AVAILABILITY - Please WAIT..."
excelapp.run "Availability.xlsb!ChangeAndCopyFile"
final vbscript code i used, for better or worse:
dim excelapp, wb
'set excelapp = createobject("excel.application")
'excelapp.enableevents=true
'excelapp.visible=true
'set wb = excelapp.workbooks.open("C:\Users\John\Desktop\ScheduledJobsfromIsaac\Availability.xlsb")
'although I don't know why the above line is silently failing, i'm going to use an alternate method I read on S.O.:
set wb = GetObject("C:\Users\John\Desktop\ScheduledJobsfromIsaac\Availability.xlsb")
set excelapp = getobject(,"excel.application")
excelapp.enableevents=true
excelapp.visible=true
excelapp.windowstate = -4137 'value for constant xlMaximized acccording to msdn
excelapp.caption = "Running AVAILABILITY - Please WAIT..."
excelapp.run "Availability.xlsb!ChangeAndCopyFile"
wb.close(true)
excelapp.caption = "10 seconds to close - please WAIT..."
wscript.sleep 10000
excelapp.displayalerts=false
excelapp.quit
probably, it helps if you can describe where and how you execute your vbscript above? is this coded in a .vbs file and execute with wscript.exe or cscript.exe, or embedded in a HTML or HTA?
If this is scripted in HTML, what browser are you using to view that? Please take note that almost all modern browsers will just ignore the vbscript silently.

Cannot make active Excel window when it is minimized

Part of my code is:
Set objShell = CreateObject("WScript.Shell")
objShell.AppActivate("Book1 - Excel")
Now i have opened afew applications in desktop and when Excel is behind others this part makes its window active. But if i minimize excel and run this part, it does not restore it.
Any ideas?
Drop that approach altogether. SendKeys is a very, very poor way of automating things and should not be used at all. If you need to automate MS Office applications use the respective COM object:
Set xl = CreateObject("Excel.Application")
xl.Visible = True
Set wb = xl.Workbooks.Add
...
wb.Close
xl.Quit
Try this. It works fine for me.
Set objShell = CreateObject("WScript.Shell")
objShell.AppActivate("Book1 - Excel")
WScript.Sleep 500 'sleep is required here to make this work
objShell.SendKeys "% x" ' to maximize

Calling an Excel sheet in VBScript

I have the following code:
Option Explicit
Randomize
Dim a, song, album
a = Int((Rnd*195)+1)
song = "B" & a
album = "A" & a
Dim objApp, objWbs, objWorkbook, objSheet
Set objApp = CreateObject("Excel.Application")
Set objWbs = objApp.WorkBooks
objApp.Visible = False
Set objWorkbook = objWbs.Open("C:\Users\Name\Documents\Music.xlsx")
Set objSheet = objWorkbook.Sheets("Sheet1")
song = objSheet.Range(song).Value
album = objSheet.Range(album).Value
objWorkbook.Close False
objWbs.Close
objApp.Quit
Set objSheet = Nothing
Set objWorkbook = Nothing
Set objWbs = Nothing
Set objApp = Nothing
MsgBox("Album name: " & album & vbNewLine & "Song name: " & song)
It prints two random cells between row 1 and row 195 from the Excel sheet "Music". One of them - the one in column A - represents the album, and the other represents the song. The problem is that it takes quite a long time to return the results, about 20 seconds.
I was wondering whether there was a more efficient method I could use to get the results more quickly.
I think Ansgar Wiechers' answer is probably correct that starting Excel is the slowest part of the script. You could try using ADO to connect to the Excel file as if it were a database. This would avoid starting Excel:
Option Explicit
Randomize
Dim conn, rst, song, album
Set conn = CreateObject("ADODB.Connection")
conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\Users\Name\Documents\Music.xlsx;" & _
"Extended Properties='Excel 12.0 Xml;HDR=NO';"
' Select a random record; reference https://stackoverflow.com/a/9937263/249624
' Asc(album) is just a way to get some numeric value from the existing data
Set rst = conn.Execute("SELECT TOP 1 F1 AS album, F2 as song FROM [Sheet1$] ORDER BY Rnd(-(100000*Asc(F1))*Time())")
If rst.EOF Then
song = "[NO RECORDS]"
album = "[NO RECORDS]"
Else
song = rst("song").Value
album = rst("album").Value
End If
MsgBox("Album name: " & album & vbNewLine & "Song name: " & song)
The one possible snag here is that VBScript is run by default using the 64-bit version of wscript.exe, and the 64-bit ACE.OLEDB is only available if you installed the 64-bit version of Office 2010 or higher. This can be worked around, though, by running the script with the 32-bit version of wscript.exe (e.g., see How do I run a VBScript in 32-bit mode on a 64-bit machine?).
If you decide to go this route and can control the input Excel file, I would recommend adding a header row to the spreadsheet and changing HDR=NO to HDR=YES in the connection string. That way, you can refer to the columns by name in the query (e.g., SELECT TOP 1 album, song ...) instead of relying on the "F1" syntax.
The most time-consuming steps in your script are most likely
starting Excel and
opening the workbook.
One thing you could do is using an already running Excel instance instead of creating a new one all the time:
quitExcel = False
On Error Resume Next
Set objApp = GetObject(, "Excel.Application")
If Err Then
Set objApp = CreateObject(, "Excel.Application")
quitExcel = True
End If
On Error Goto 0
The variable quitExcel indicates whether you need to close Excel at the end of your script (when you created a new instance) or not (when you used an already running instance).
You could also check if the workbook is already open:
wbOpen = False
For Each wb In objWbs
If wb.Name = "Music.xlsx" Then
Set objWorkbook = wb
wbOpen = True
Exit For
End If
Next
If Not wbOpen Then
Set objWorkbook = objWbs.Open("C:\Users\Name\Documents\Music.xlsx")
End If
Other than that your only options are changing the way the data is stored or buying faster hardware, AFAICS.
Cheran, I disagree with the answers here.
I just ran your script on my 5 year old laptop, and got the answer in about 2 seconds. Whether an instance of Excel was already open made no difference in run time.
(I created a test Music.xlsx spreadsheet by entering "A1" in cell A1, and "B1" in cell B1, and dragged those cells down to row 195 to get a nice set of unique sample data).
Why don't you make Excel visible when it runs, so that you can see for yourself what is going on?
You might see, for example, that Excel takes one second to open, and the Excel Add-ins you have are taking the other fifteen seconds to initialize. It's also possible that your machine and/or hard drive is slow and does indeed take 20 seconds to run this. Who knows...
To get some insight, please make objApp.Visible = True and rerun.
You might also comment out the final eight lines, except for the MsgBox line so that your Excel file stays open after script is done, so that you might see other clues.
Other observations:
1) Your method of opening Excel with CreateObject from a .vbs script seems to be the most reliable/accepted method of automating Excel.
2) It's not stated here HOW you are running the .vbs script (command line vs. double-click from Explorer). Your script is running, but be aware that using cscript.exe to run the .vbs is also common when people try to automate this.
3) I'm not used to seeing an external vbs interact with the data inside Excel...I'm used to having vbs open Excel.xlsm, then letting a Macro do the number crunching. But, Macros bring an entirely different set of headaches. I'm not saying your method is good or bad...just not used to that approach.
Good luck!

How to automate the forced closure of excel, followed by a restart?

Occasionally excel freezes or crashes while performing some long running VBA code (runs 24hr/day) and I'm examining ways to handle the restart of excel programmatically. Any advice on best way to go about this would be appreciated.
One idea i have is to write a dotnet app that might be potentially triggered by, say, a windows logging error event such as 'Event Name: APPCRASH' and 'Faulting application EXCEL.EXE', but i have no idea if this is feasible/sensible way to go about it.
If it happens to be a sensible approach, i would envisage the app potentially performing the following tasks;
1) Auto close/cancel any windows error popup boxes such as "Do you want to send more information about the problem?", "Microsoft Excel has stopped working", or "Microsoft Excel is trying to recover your information."
2) Force close excel if still open (eg if hanging), as well as killing any excel.exe processes
3) Restart excel
Is is possible to write such an app in dotnet? What references/tags should i be looking for to find further information?
Thanks,
Yug
After some digging, I pieced together the following solution. The vbs code below will force taskkill any outstanding excel.exe processes, and then opens the stated excel file (from which vba code can be restarted automatically from a worksheet_open event).
1) Turn off Windows error reporting:
Start, search 'Problem Reports and Solutions', change settings, advanced settings, Turn off problem reporting
2) Disable auto recovery for excel:
Within the WB in question, click; file, options, save, disable file recovery for this WB only
3) Under windows event viewer, application logs, highlight the error (faulting excel app) , right click 'create a basic task', run application/script, and enter the chosen name of the file in 4).
4) Paste the following code into text file and save as a vbScript file (.vbs)
Option Explicit
KillProcesses
ExcelRestart
Sub ExcelRestart()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
xlApp.DisplayAlerts = False
Set xlBook = xlApp.Workbooks.Open("C:\...\test.xlsx")
xlApp.visible = True
xlBook.activate
Set xlBook = Nothing
Set xlApp = Nothing
End sub
Sub KillProcesses
On error resume next
Dim objWMIService, WshShell
Dim proc, procList
Dim strComputer, strCommand
strCommand = "taskkill /F /IM excel.exe"
strComputer = "."
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:"& "{impersonationLevel=impersonate}!\\"& strComputer & "\root\cimv2")
Set procList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'excel.exe'")
For Each proc In procList
WshShell.run strCommand, 0, TRUE
Next
End sub

Resources