How to call java object in VBA with classpath - vba

We use a CMD to call a PowerShell script. In the PowerShell script, a Java program is called. Both files are in the same directory. I want this all replaced by VBA within Microsoft Access. I have found several related topics but I can't decide whether it is possible or not based on these topics. Topics like Launch jar file from VBA code
The CMD contains the following code:
SET CLASSPATH=.\yyyyy.jar
powershell .\startscript.ps1
The PowerShell script contains the following sample:
& java '-Djavax.net.ssl.trustStore="zzzz.keystore"' com.router.router.router.Router -user:... etc.
We also run the same Java program in a different setting, only with the use of one .CMD-file. This is made like:
SET USR=user
SET CLASSPATH=.\yyyyy.jar
java -Djavax.net.ssl.trustStore=zzzz.keystore com.router.router.router.Router -user:%USR% etc.
Preferably both PowerShell and CMD become obsolete and the parameters like "-user" are fed with variables from the VBA code.
Does someone have a usable link, example or code? Please advice.

What you are trying to do is to run a command via the command line. It just happens that this command runs java, as far as the VBA code is concerned it may run anything that the shell would understand.
A sample code to run a command via a shell in VBA is the following (note there are many ways and it's super easy to find these samples on internet, I'm just using the first one I found):
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = False
Dim windowStyle As Integer: windowStyle = 1
wsh.Run "cmd.exe /S /C " & yourCommand
... where yourCommand is the litteral string you would run in your command prompt. Now, it's all about string concatenation in VBA. Following your sample (and adding the username directly from VBA):
user = Environ("UserName")
yourCommand = "java -Djavax.net.ssl.trustStore=zzzz.keystore com.router.router.router.Router -user:" & user
(please note that I replaced %USR% - which asks the shell to retrieve the username - with a variable user that I've defined in VBA, even though in this specific example, the function Environ is asking environment variables so it's still asking it to a shell).

Related

Shell hitting Run-Time error '5' trying to call R script in Access VBA

I made a simplified version of my code that directly highlights the issue.
I have read dozens of similar issues/solution.
Part of my workflow in VBA in Microsoft Access involves calling an R script that does some logic and returns information to a table in the same database.
It was working until we moved the location of the R installation to a new drive. Changing the path to this new install location does not work. No other code is changed.
cmd = "C:\R\bin\i386\Rscript.exe C:\R\test.R"
Debug.Print cmd
Shell cmd
I get
runtime error '5'
I am using the immediate window to check the paths are correct and copying them into RUN to verify that they do work.
The above outputs:
C:\R\bin\i386\Rscript.exe C:\R\test.R
It works in RUN.
The first thing I found when searching online is to add more (") as shell can handle them weirdly:
cmd = """C:\R\bin\i386\Rscript.exe""" & " " & """C:\R\test.R"""
Or any iterations of using "s in different places, output:
"C:\R\bin\i386\Rscript.exe" "C:\R\test.R"
Same error but works in RUN. I also tried them all successfully in CMD.
It seems just Shell refuses to launch R from that path. I have moved it elsewhere on my C drive with same effect.
I cannot recreate the original R installation path as that shared drive is now completely dead.
EDIT:
I changed to using ShellExecute simply to try and make Notepad ++ open, again works in cmd.
Set objShell = CreateObject("Shell.Application")
objShell.ShellExecute "C:\N\notepad++.exe", "C:\R\test_in.csv", "", "open", 1
This time I hit a "suspicious macro error" that leads me to believe that it may be an antivirus setting (macros are enabled in Access) blocking Shell from calling anything.
After days of testing I have found the solution, hopefully this can help anyone else in a similar situation. Windows Defender only blocks shell calls to non-Microsoft products, so I nested a call to PowerShell within the call to Shell:
Shell ("powershell.exe C:\R\bin\i386\Rscript.exe C:\R\test.R")
Take note you need to play around with the "s a lot ot get it working, my actual pipeline has more arguments and I had to enclose them in 5 sets of "s for it to pass through to powershell properly. IE:
Dim codePath As String: codePath = """""\\example\example"""""
Try these variations using Start or a second Command:
cmd = "Start C:\R\bin\i386\Rscript.exe C:\R\test.R"
or:
cmd = "cmd /c ""C:\R\bin\i386\Rscript.exe C:\R\test.R"""

Error executing batch file in excel VBA windows

I was trying to execute a batch file via standard call shell() function.
This Batch file is project specific and created automatically for each project by an external application. Main function is to normalise around 40 files having statistical data used for my project. This data is being acquired form excel. While executing manually this takes around 30 seconds for the complete process and its working just fine.
When I try to access this using call shell function in VBA, It just pop up for like 2 seconds and outputs were not generated from Batch file.
I am attaching My sample code below used for this. I am just baby-stepping in VBA Macros. Please Excuse my coding practice.
Call Shell(Range("L8") & "\DSTAT$.BAT")
I tried this also
`Dim Runcc
Runcc = Shell(Range("L8") & "\DSTAT$.BAT", 1)`
Please let me know if any further information is required to sort this out.
Try
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
With CreateObject("WScript.Shell")
.Run Range("L8") & "\DSTAT$.BAT", windowStyle, waitOnReturn
End With
I use this for converting PDFs to JPG with Irfanview on report_open in Ms-Access.
Stolen from vba WScript.Shell run .exe file with parameter

Environment Variables not recognized when calling Run in WScript.Shell object

If I run the command Rscript "C:/TEMP/test.R" in the command line it works and my script runs as expected. Once I try to run it in my VBA code it does not recognize the Rscript as a valid command.
Dim shell_obj As Object
Set shell_obj = VBA.CreateObject("WScript.Shell")
Dim errorCode As Integer
errorCode = shell_obj.Run("Rscript ""C:/TEMP/test.R""", 1, True)
When I looked into the PATH variable being used by the WScript.Shell I saw that it does not include the System Variables with the Rscript path inside of it.
Dim shell_obj As Object
Dim wshSystemEnv As Object
Set shell_obj = VBA.CreateObject("WScript.Shell")
' This one does not include the path to the Rscript'
Debug.Print shell_obj.ExpandEnvironmentStrings("%PATH%")
Set wshSystemEnv = shell_obj.Environment("SYSTEM")
' This one includes the path to the Rscript'
Debug.Print wshSystemEnv("PATH")
Can I force the the WScript.Shell object to use the System environment? Or at least use its variables?
Cmd:
VBA (version 1):
VBA (version 2):
EDIT: See bottom of post.
Hopefully you'll find some use in my (lengthy) take on this... :-)
Testing for command-line readiness
Any command (including an RScript) that can be run as-is from the Windows command-line can also be run with either the VBA Shell function or the Windows WScript.Shell method.
The issue is, your cmd string is not command-line ready. This can be confirmed by hitting +R and pasting the contents of your cmd string variable:
Rscript "**path**/test.R"
I don't currently have rscript.exe installed but I suspect you will get an error if you try running your command manually in either the Run window or on the command line. If it doesn't run there it obviously won't run with in a VBA Shell.
As I understand it, the double asterisk is a Java notation the way you are using it, and in R is the same as a ^ caret character, which is for calculating exponents.
Referencing an environment variable
To return the Windows PATH environment variable in VBA, you would use VBA's Environ function.
To insert the value environment variable inline at the command line, you would surround it with %percent% symbols, like %path%
Windows' PATH environment variable
PATH does not return a single folder. It's a list of folders that Windows should check to find an executable file that one attempts to run.
When a command is entered in a command shell or a system call is made by a program to execute a program, the system first searches the current working directory and then searches the path, examining each directory from left to right, looking for an executable filename that matches the command name given.
The Windows system directory (typically C:\WINDOWS\system32) is typically the first directory in the path, followed by many (but not all) of the directories for installed software packages.
An example a default value of PATH (from a fresh install of Windows 7) is:
%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem
As with %path%, this includes%SystemRoot%` which, by default on Windows 7 is the string:
C:\Windows
Checking environment variables
You can verify the value of your PATH environment label:
Hit +R.
Type cmd and hit Enter. (A command line window should open.)
Type or paste echo %path% and hit Enter.
The contents of the Window PATH environment variable will be displayed.
You can also check environment variables from within Windows:
and type env (to search)
Click Edit the system environment variables. (There is a similar option "...for your account" which is not quite the same.)
Click
Note: Although you technically can change the PATH in this window, I would not recommend doing so, especially with PATH since it is split up into System and User folders, and Windows likes certain folders in certain areas, and some changes don't take effect until reboot but others do, and blah blah blah, trust me: it's easier to do from the command line.
What's wrong with your code?
Therefore it based on all of this, it appears that the command you're trying to run is:
Rscript "C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem/test.R"
...which obviously will not work.
Get or set the current working folder/directory
I can only speculate as to what you're trying to accomplish.
I suspect you didn't intend to return the entire PATH variable, but are only interested in the current working folder.
If so, you don't need to specify a folder at all. Shell already commands execute in the "current" folder.
One way you can check which directory or folder is current, is with the VBA CurDir() function, like:
Debug.Print CurDir()
The value of CurDir can be changed with the ChDir statement.
Similar functions
Note that the CurDur() command is often confused with similar functions like:
Application.Path which returns the path to the Excel application, or,
ActiveWorkbook.Path which returns the location that the active workbook is saved (or an empty string if it's unsaved).
Possible Solution: (How to run an rScript in the current path in VBA)
If your R script and the rscript.exe are both in the current working folder, run it with just one line of VBA:
Shell "rscript.exe test.R", vbNormalFocus
If you require VBA to wait for execution of the Shell command to complete before resuming VBA, then you can you just this one line:
CreateObject("WScript.Shell").Run "rscript.exe test.R", vbNormalFocus, True
More Information:
I generally make a point of including links to any sites I used to verify my answers, so this must be my most-researched answer yet because I've never had a list this long... and I left some off out this time!
Stack Overflow : Running R scripts from VBA
MSDN : Shell Function (VBA)
MSDN : Environ Function (VBA)
R-Bloggers : Passing arguments to an R script from command lines
Stack Overflow : R.exe, Rcmd.exe, Rscript.exe and Rterm.exe: what's the difference?
Stack Exchange: Statistics : Double star ** in R?
Wikipedia : PATH (variable)
Stack Overflow : Default values of PATH variable in Windows 10
SuperUser : Default PATH for Windows 7
MSDN : CurDir() Function (VBA)
MSDN : ChDir() Statement (VBA)
MSDN : Application.Path (Excel/VBA)
MSDN : ActiveWorkbook.Path (Excel/VBA)
Stack Overflow : Wait for Shell command to complete
MSDN Forums : Difference between wscript.shell and shell.application
Stack Overflow : Steps to run R script through Windows command prompt
One More Demo of What's Wrong With Your Code:
I have a batch file named test.bat located in C:\WINDOWS. My PATH environment variable contains C:\WINDOWS (among other things).
If I go to the command prompt in root folder C:\ and type test.bat:
...it runs properly (even though my file is not in that folder... since the c:\windows folder is within the PATH variable.)
However, if I go to the command prompt and type C:\test.bat:
...it does not work. It cannot find the file because I specified a folder where the file is not located.
--- In VBA, if I run the command Shell "test.bat",1:
...it runs properly (even though my file is not in that folder... since the c:\windows folder is within the PATH variable.)
However, if in VBA I run the command Shell "c:\test.bat",1:
...it does not work. It cannot find the file because Ispecified* a folder where the file is not located**.
Both VBA and the Shell command are behaving the same way, when given the same information.
If you have recently modified the system PATH variable, you must restart the Office application you are running VBA from. VBA sends WScript the path variable and only rereads it on a restart. On restart, it will reread the PATH variable from the system and send the new correct path to WScript.
I had the same issue. I had updated the system PATH variable, but the WScript.Shell object was being passed the path variable from Excel rather than reading from the system. Excel had read the path at startup and was not aware it had changed. Once I closed Excel and reopened, WScript had the updated path variable and my script execute successfully.

Getting shell cmd output to Excel

I have a macro in VBA (Excel 2007).
It opens an exe file with entering a HEX value as variable.
The exe gives the output (also a HEX number).
I do everything with "shell" command and the results is saved to a txt file. Then I write this to Excel.
retVal = Shell("cmd.exe /c C:\AABB\app.exe 0x5110 > C:\AABB\output.txt", vbNormalFocus)
It is complicated and time-consuming.
I would prefer getting the result directly to Excel, without an intermediate file like txt or similar.
When I use an output.xlsx as output destination, the file is created and the value is written. But I cant read it with Excel. I see the value when I open the xlsx with Notepad.
My questions are:
1) Is it possible to write the result directly to xlsx, especially a target cell e.g. A10
2) Why when I use xlsx as destination in shell command, I can't open it with Excel? It gives Error Message of "file-format or file-extension is not valid. Data might be corrupted".
I think you can't do that with shell object.
you can do it with WSHExec with the function StdOut.ReadLine().
You have to go to reference and choose "Windows Script Host object model" so you can declare a WshExec object. than see the Method yourWshExecObject.StdOut.ReadLine().
To construct WshExec :
First declare a WshShell Object and you construct it like that :
Dim WshShellObject as WshShell
Dim WshExecObject as WshExec
Set WshShellObject = New WshShell
Set WshExecObject = WshShellObject.Exec("your .exe filename").
The WshExecObject.StdOut TextStream will read everything you write in the console.
I did it with an .exe compilated with C++.
You can also use WshExecObject.StdOut.ReadAll to read all lines at once.
Hope that helps.

WMI remote process to copy file

Long story short, my application needs to copy a file to a remote target where UNC connections TO the target might not be possible. However UNC connections FROM the target and BACK to the server will always be possible. So the plan was to use WMI to start a remote command shell (cmd) and use the copy command to grab the file. But this doesn't work. The following command works fine when executed manually from the command line of the target:
copy \\192.168.100.12\c$\remotefile.txt c:\localfile.txt
But when I try this same command as part of the InputParameters("CommandLine") it does not work, and produces no error. Note that I can use WMI to connect to the target and remote execution works just fine as I can start calc.exe etc. Here is the code that doesn't work:
Dim ConnectionOptions As New System.Management.ConnectionOptions
With ConnectionOptions
.Username = "target\Administrator"
.Password = "password"
End With
Dim ManagementScope As New System.Management.ManagementScope("\\192.168.100.11\root\cimv2", ConnectionOptions)
Try
ManagementScope.Connect()
MsgBox("connected")
Dim ManagementPath As New System.Management.ManagementPath("Win32_Process")
Dim ManagementOptions As New System.Management.ObjectGetOptions
Dim ManagementClass As New System.Management.ManagementClass(ManagementScope, ManagementPath, ManagementOptions)
Dim InputParameters As System.Management.ManagementBaseObject = ManagementClass.GetMethodParameters("Create")
InputParameters("CommandLine") = "cmd /c copy \\192.168.100.12\c$\remotefile.txt c:\localfile.txt"
Dim OutputParameters As System.Management.ManagementBaseObject = ManagementClass.InvokeMethod("Create", InputParameters, Nothing)
MsgBox("done")
Catch ex As Exception
MsgBox(ex.Message)
End Try
Any ideas why this isn't working? Or does anyone have a better way of doing what I'm trying to do?
Frank you should actually give yourself credit since the method you created is likely the first ever to get around WMI limitations of remote file copy! I did 3 weeks of searching for info/workaround and yours is the only one that works! If I had any points I would vote for your solution...
I created a fully working VBS & WMI script based on your method:
InputParameters("CommandLine") = "cmd /c echo myFTPCommands > c:\ftpscript.txt"
where you replace myFTPCommands as needed with whatever script you want to go into the file c:\ftpscript.bat (or .vbs, .ps1, or whatever you like). If you couldn't fit enough text in the one-line script, then append with the same method using >>. Now, you can use XCOPY, PSEXEC, COPY, or anything else to run the script you just created on the remote host's file system.
Here's my fully fleshed out VBScript using your method. Thanks again. :)
HTH,
Lizz
For security reasons, most methods of programatically connecting to a remote machine and telling it to copy a file to itself from another machine are blocked. One thing that finally worked for me is FTP. Using the above code I can do something like this:
InputParameters("CommandLine") = "ftp -s:c:\ftpscript.txt"
Which causes the ftp commandline utility to run on the remote machine, using c:\ftpscript.txt to get a list of commands from. Since there is no way to copy the ftp script file to the target (again, no UNC connection), I can first do:
InputParameters("CommandLine") = "cmd /c echo myFTPCommands > c:\ftpscript.txt"
And this works :)
UPDATE: Never thought to use XCOPY and it works perfectly:
InputParameters("CommandLine") = "cmd /c echo F | xcopy remotefile localfile"
UPDATE: XCOPY worked yesterday, now it doesn't. NOTHING has changed, so I am at a complete loss for explanation.