I have an Excel VBA macro which I need to run when accessing the file from a batch file, but not every time I open it (hence not using the open file event). Is there a way to run the macro from the command line or batch file? I'm not familiar with such a command.
Assume a Windows NT environment.
You can launch Excel, open the workbook and run the macro from a VBScript file.
Copy the code below into Notepad.
Update the 'MyWorkbook.xls' and 'MyMacro' parameters.
Save it with a vbs extension and run it.
Option Explicit
On Error Resume Next
ExcelMacroExample
Sub ExcelMacroExample()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\MyWorkbook.xls", 0, True)
xlApp.Run "MyMacro"
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
The key line that runs the macro is:
xlApp.Run "MyMacro"
The simplest way to do it is to:
1) Start Excel from your batch file to open the workbook containing your macro:
EXCEL.EXE /e "c:\YourWorkbook.xls"
2) Call your macro from the workbook's Workbook_Open event, such as:
Private Sub Workbook_Open()
Call MyMacro1 ' Call your macro
ActiveWorkbook.Save ' Save the current workbook, bypassing the prompt
Application.Quit ' Quit Excel
End Sub
This will now return the control to your batch file to do other processing.
The method shown below allows to run defined Excel macro from batch file, it uses environment variable to pass macro name from batch to Excel.
Put this code to the batch file (use your paths to EXCEL.EXE and to the workbook):
Set MacroName=MyMacro
"C:\Program Files\Microsoft Office\Office15\EXCEL.EXE" "C:\MyWorkbook.xlsm"
Put this code to Excel VBA ThisWorkBook Object:
Private Sub Workbook_Open()
Dim strMacroName As String
strMacroName = CreateObject("WScript.Shell").Environment("process").Item("MacroName")
If strMacroName <> "" Then Run strMacroName
End Sub
And put your code to Excel VBA Module, like as follows:
Sub MyMacro()
MsgBox "MyMacro is running..."
End Sub
Launch the batch file and get the result:
For the case when you don't intend to run any macro just put empty value Set MacroName= to the batch.
you could write a vbscript to create an instance of excel via the createobject() method, then open the workbook and run the macro. You could either call the vbscript directly, or call the vbscript from a batch file.
Here is a resource I just stumbled accross:
http://www.codeguru.com/forum/showthread.php?t=376401
If you're more comfortable working inside Excel/VBA, use the open event and test the environment: either have a signal file, a registry entry or an environment variable that controls what the open event does.
You can create the file/setting outside and test inside (use GetEnviromentVariable for env-vars) and test easily. I've written VBScript but the similarities to VBA cause me more angst than ease..
[more]
As I understand the problem, you want to use a spreadsheet normally most/some of the time yet have it run in batch and do something extra/different. You can open the sheet from the excel.exe command line but you can't control what it does unless it knows where it is. Using an environment variable is relatively simple and makes testing the spreadsheet easy.
To clarify, use the function below to examine the environment. In a module declare:
Private Declare Function GetEnvVar Lib "kernel32" Alias "GetEnvironmentVariableA" _
(ByVal lpName As String, ByVal lpBuffer As String, ByVal nSize As Long) As Long
Function GetEnvironmentVariable(var As String) As String
Dim numChars As Long
GetEnvironmentVariable = String(255, " ")
numChars = GetEnvVar(var, GetEnvironmentVariable, 255)
End Function
In the Workbook open event (as others):
Private Sub Workbook_Open()
If GetEnvironmentVariable("InBatch") = "TRUE" Then
Debug.Print "Batch"
Else
Debug.Print "Normal"
End If
End Sub
Add in active code as applicable. In the batch file, use
set InBatch=TRUE
Instead of directly comparing the strings (VB won't find them equal since GetEnvironmentVariable returns a string of length 255) write this:
Private Sub Workbook_Open()
If InStr(1, GetEnvironmentVariable("InBatch"), "TRUE", vbTextCompare) Then
Debug.Print "Batch"
Call Macro
Else
Debug.Print "Normal"
End If
End Sub
I have always tested the number of open workbooks in Workbook_Open(). If it is 1, then the workbook was opened by the command line (or the user closed all the workbooks, then opened this one).
If Workbooks.Count = 1 Then
' execute the macro or call another procedure - I always do the latter
PublishReport
ThisWorkbook.Save
Application.Quit
End If
# Robert: I have tried to adapt your code with a relative path, and created a batch file to run the VBS.
The VBS starts and closes but doesn't launch the macro... Any idea of where the issue could be?
Option Explicit
On Error Resume Next
ExcelMacroExample
Sub ExcelMacroExample()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")
strFilePath = objFSO.GetAbsolutePathName(".")
Set xlBook = xlApp.Workbooks.Open(strFilePath, "Excels\CLIENTES.xlsb") , 0, True)
xlApp.Run "open_form"
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
I removed the "Application.Quit" because my macro is calling a userform taking care of it.
Cheers
EDIT
I have actually worked it out, just in case someone wants to run a userform "alike" a stand alone application:
Issues I was facing:
1 - I did not want to use the Workbook_Open Event as the excel is locked in read only.
2 - The batch command is limited that the fact that (to my knowledge) it cannot call the macro.
I first wrote a macro to launch my userform while hiding the application:
Sub open_form()
Application.Visible = False
frmAddClient.Show vbModeless
End Sub
I then created a vbs to launch this macro (doing it with a relative path has been tricky):
dim fso
dim curDir
dim WinScriptHost
set fso = CreateObject("Scripting.FileSystemObject")
curDir = fso.GetAbsolutePathName(".")
set fso = nothing
Set xlObj = CreateObject("Excel.application")
xlObj.Workbooks.Open curDir & "\Excels\CLIENTES.xlsb"
xlObj.Run "open_form"
And I finally did a batch file to execute the VBS...
#echo off
pushd %~dp0
cscript Add_Client.vbs
Note that I have also included the "Set back to visible" in my Userform_QueryClose:
Private Sub cmdClose_Click()
Unload Me
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
ThisWorkbook.Close SaveChanges:=True
Application.Visible = True
Application.Quit
End Sub
Anyway, thanks for your help, and I hope this will help if someone needs it
I'm partial to C#. I ran the following using linqpad. But it could just as easily be compiled with csc and ran through the called from the command line.
Don't forget to add excel packages to namespace.
void Main()
{
var oExcelApp = (Microsoft.Office.Interop.Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
try{
var WB = oExcelApp.ActiveWorkbook;
var WS = (Worksheet)WB.ActiveSheet;
((string)((Range)WS.Cells[1,1]).Value).Dump("Cell Value"); //cel A1 val
oExcelApp.Run("test_macro_name").Dump("macro");
}
finally{
if(oExcelApp != null)
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcelApp);
oExcelApp = null;
}
}
I generally store my macros in xlam add-ins separately from my workbooks so I wanted to open a workbook and then run a macro stored separately.
Since this required a VBS Script, I wanted to make it "portable" so I could use it by passing arguments. Here is the final script, which takes 3 arguments.
Full Path to Workbook
Macro Name
[OPTIONAL] Path to separate workbook with Macro
I tested it like so:
"C:\Temp\runmacro.vbs" "C:\Temp\Book1.xlam" "Hello"
"C:\Temp\runmacro.vbs" "C:\Temp\Book1.xlsx" "Hello" "%AppData%\Microsoft\Excel\XLSTART\Book1.xlam"
runmacro.vbs:
Set args = Wscript.Arguments
ws = WScript.Arguments.Item(0)
macro = WScript.Arguments.Item(1)
If wscript.arguments.count > 2 Then
macrowb= WScript.Arguments.Item(2)
End If
LaunchMacro
Sub LaunchMacro()
Dim xl
Dim xlBook
Set xl = CreateObject("Excel.application")
Set xlBook = xl.Workbooks.Open(ws, 0, True)
If wscript.arguments.count > 2 Then
Set macrowb= xl.Workbooks.Open(macrowb, 0, True)
End If
'xl.Application.Visible = True ' Show Excel Window
xl.Application.run macro
'xl.DisplayAlerts = False ' suppress prompts and alert messages while a macro is running
'xlBook.saved = True ' suppresses the Save Changes prompt when you close a workbook
'xl.activewindow.close
xl.Quit
End Sub
You can check if Excel is already open. There is no need to create another isntance
If CheckAppOpen("excel.application") Then
'MsgBox "App Loaded"
Set xlApp = GetObject(, "excel.Application")
Else
' MsgBox "App Not Loaded"
Set wrdApp = CreateObject(,"excel.Application")
End If
I'm trying to run an Access Macro from VBA and keep getting error:
Run-time Error 2485; Access cannot find the object 'MyTest'
My code is below - it is odd because the line:
A.DoCmd.OpenModule "temp", "MyTest"
works (opens the module to the correct location).
The macro is a simple test one; all paths are correct so far as I can tell. Thanks!
Set A = Nothing
Set A = CreateObject("Access.Application")
A.Visible = False
A.OpenCurrentDatabase (DBFileName)
A.DoCmd.OpenModule "temp", "MyTest"
A.DoCmd.RunMacro "MyTest"
A.CloseCurrentDatabase
A.Quit
Set A = Nothing
I am not sure if this is what you are looking for, but the following Excel macro starts the macro "MyTest" from a module which is included in the Access file "filename":
Sub test_accesss()
Set A = Nothing
Set A = CreateObject("Access.Application")
A.Visible = False
A.OpenCurrentDatabase ("filename")
A.Run "MyTest"
A.CloseCurrentDatabase
A.Quit
Set A = Nothing
End Sub
I have three workbooks, a parent book, a library book and a log book.
The parent book opens a library, and then closes the library. Coincidentally the library has a provision in the workbooks on open and before close events to write to a log book whenever it is opened or closed.
My issue is that when the library is opened programmatically from the parent book, the code to open the log book before close is skipped over. I get no errors, it just simply evaluates the line and produces no result.
CODE:
From my parent book I run this line:
...
Workbooks(parts_library_name).Close savechanges:=True
...
Which runs this code in the library book:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Set libwkb = ThisWorkbook
'last call to backup usage sheet
backup_exit_size
'exit
End Sub
Sub backup_exit_size()
Dim bypass_close_usage_library As Boolean
Application.DisplayAlerts = False
file_size_at_close = FileLen(ThisWorkbook.Path & "\" & ThisWorkbook.Name)
For Each Workbook In Workbooks
If Workbook.Name = "usage_library.xlsx" Then bypass_close_usage_library = True
Next
Application.ScreenUpdating = False
If bypass_close_usage_library = False Then
Workbooks.Open "somepath\usage_library.xlsx"
End If
Workbooks("usage_library.xlsx").Worksheets("usage").Cells(next_row_usage_library, 3) = file_size_at_close
Workbooks("usage_library.xlsx").Close savechanges:=True
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
The problem is that when it gets to this line:
Workbooks.Open "somepath\usage_library.xlsx"
the compiler simply skips over the command.
That is only the case however if I get to the beforeClose event that originated from another Book. If I close the book from itself, the macro runs fine and opens the log book fine.
I have tried a with statement from the parent book, like
With library.xlsx
.RunAutoMacros xlAutoClose
.Close
End With
but have the same results, it evaluates the line and then skips over it.
Thoughts?
I'm seeing the same behavior. I even tried using WithEvents.
As a workaround, you can open the new workbook in a new instance of Excel:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim xlapp As New Excel.Application
Dim wb As Workbook
Set wb = xlapp.Workbooks.Open("\\...\test.xlsb")
xlapp.Visible = True 'This line just proves that it works and can be removed'
'do stuff
xlapp.Quit
Set wb = Nothing
Set xlapp = Nothing
End Sub
Here is my solution as of right now:
...
Application.Run (parts_library_name & "!backup_exit_size")
Workbooks(parts_library_name).Close savechanges:=True
...
this works but may not be ideal.
I've identified the issue to be inherent with application.screenupdating = false. It works just fine if you turn this off right before your workbook open command.
I'm struggling with a VBA Sub that is called by a button. This Sub opens an Configuration.xls Excel spreadsheet from a hard coded file path. A MsgBox tell me about the current workspace - the workspace changes from the current file to the just opened one. All is fine here.
I now want to execute this Sub from an outside batch that calls a VBS that calls the VBA Sub. The workspace after opening the Configuration.xls file remains the same and does not change to Configuration.xls. Additionally when calling the Sub by VBS the function gets executed twice - No clue why.
So my question is - why do I have different behaviors between the two calling mechanisms?
I simplified the code below as it shows the same behavior as my more complex real code.
Sub ReadConfiguration()
MsgBox ActiveWorkbook.Name
FileExcel = "D:\_Trash\VBA_VBS\Configuration.xls"
Workbooks.Open Filename:=FileExcel, ReadOnly:=True, IgnoreReadOnlyRecommended:=True
strFileName = FunctionGetFileName(FileExcel)
MsgBox ActiveWorkbook.Name
On Error Resume Next
Set wBook = Workbooks(strFileName)
If Err Then
Exit Sub
End If
ActiveWorkbook.Close savechanges:=False
End Sub
'*****************************************************
Function FunctionGetFileName(FullPath As Variant)
Dim StrFind As String
Do Until Left(StrFind, 1) = "\"
iCount = iCount + 1
StrFind = Right(FullPath, iCount)
If iCount = Len(FullPath) Then Exit Do
Loop
FunctionGetFileName = Right(StrFind, Len(StrFind) - 1)
End Function
'*****************************************************
The VBS looks like this
Dim args, objExcel
Set args = WScript.Arguments
Set objExcel = CreateObject("Excel.Application")
objExcel.Workbooks.Open args(0)
objExcel.Visible = False
objExcel.Run "Module1.ReadConfiguration()"
objExcel.ActiveWorkbook.Close(0)
objExcel.Quit
I just want to let you know about the solution of this issue allthough I cannot explain completely. The solution is to get rid of the "()" behind the macro call. This has the effect that the VBS script is run twice and the Workbook 'scope' is mixed up.
So easy solution but still the question WHY- What do I tell the function additionally when adding the "()"?
Thanks for your help!
TheMadMatt
Let's say I want to program a VBA code in an external program that opens an Excel file, runs a macro, saves (and say yes to any pop up windows), and close Excel. Is it possible to do so? If so, how would I go about implementing it?
You can launch Excel, open a workbook and then manipulate the workbook from a VBScript file.
Copy the code below into Notepad.
Update the 'MyWorkbook.xls' and 'Sheet1' parameters.
Save it with a vbs extension and run it.
Option Explicit
On Error Resume Next
ExcelMacroExample
Sub ExcelMacroExample()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\MyWorkbook.xls")
xlBook.Sheets("Sheet1").Cells(1, 1).Value = "My text"
xlBook.Sheets("Sheet1").Cells(1, 1).Font.Bold = TRUE
xlBook.Sheets("Sheet1").Cells(1, 1).Interior.ColorIndex = 6
xlBook.Save
xlBook.Close
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
This code above launches Excel opens a workbook, enters a value in cell A1, makes it bold and changes the colour of the cell. The workbook is then saved and closed. Excel is then closed.
Depending on what you are trying to achieve you may also 'control' Excel via (OLE) Automation from another application such as Access or Word or from your own application written in another environment such as Visual Basic (6). It is also possible to achieve this via .Net using a language of your choice (although some are easier to implement than others).
Are you wanting to control Excel from an external application or simply trigger a VBA macro in an existing workbook from the outside?
Again, depending on your intention, the workbook could have an Auto Open macro which could be conditional run based on an external value (say an ini file or database value).
I can think of several ways to do this.
You can start excel by creating a file with NotePad or a similar text editor.
Here are some steps:
Launch NotePad
Add the following line of text. Replace test.xlsm with the name and path for your file:
start Excel.exe "C\test.xlsm"
Save the file as "Test.bat".
Run the batch file.
The batch file should launch Excel and then open your file. The code in your workbook should run
OR
Again, using Notepad.
Option Explicit
On Error Resume Next
ExcelMacroExample
Sub ExcelMacroExample()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\MyWorkbook.xls", 0, True)
xlApp.Run "MyMacro"
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
Or, this.
'Code should be placed in a .vbs file
Set objExcel = CreateObject("Excel.Application")
objExcel.Application.Run "'C:\Users\Ryan\Desktop\Sales.xlsm'!SalesModule.SalesTotal"
objExcel.DisplayAlerts = False
objExcel.Application.Quit
Set objExcel = Nothing
Now, this isn't 'an external command', but the Windows Task Scheduler will do a nice job of opening that file for you, and once it is opened, you can run a tiny script like the one you see below.
Private Sub Workbook_Open()
Call CommandButton1_Click
End Sub
https://www.sevenforums.com/tutorials/11949-elevated-program-shortcut-without-uac-prompt-create.html