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.
Related
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"""
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).
I have a VB.net app where I invoke Import-Module on a PowerShell from within my vb.net Window Application but the error says it could not find the module. Error as below.
Import-Module : The specified module 'MSOnline' was not loaded because no valid module file was found in any module directory.
When I load the same Module by launching the PowerShell externally in the usual way it works fine. Image as below.
The VB script is as below
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim procStartInfo As New ProcessStartInfo
Dim procExecuting As New Process
With procStartInfo
.UseShellExecute = True
.FileName = "powershell.exe"
.WindowStyle = ProcessWindowStyle.Normal
.Verb = "runas" 'add this to prompt for elevation
Dim psscript As String = My.Resources.mymsolPS
procStartInfo.Arguments = psscript
procExecuting = Process.Start(procStartInfo)
End With
End Sub
My PowerShell Script is saved in my.resource as a txt file. My PowerShell Script is as below.
Import-Module Msonline
Connect-msolService
I replaced the PowerShell script to Get-Help and that works only it dosnt work when I use Import-Module Msonline.
One more information that can be shared is the module is stored in the below location.
C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline\MSOnline.psd1
Any Help is greatly appreciated.
Thanks in Advance
Update 2:
More fiddling with it found some thing which i am not sure if is relevant.
If I launch the powershell from within my VB.net and run the below command I cant see the MSOnline module.
PS C:\windows\system32>> cd $env:WINDIR\System32\WindowsPowerShell\v1.0\Modules\
PS C:\windows\System32\WindowsPowerShell\v1.0\Modules>> dir
If I run the PowerShell directly from my system and run the above script I can see the Module
d----- 11/22/2017 2:59 PM MSOnline
Still a mystery for me which I cant crack. :(
A difference I notice is when launching from your app, or locally, the directory is either your user, or system.. so maybe the way PS is being loaded it can't find the module.
What about if you provide a full path to the module?
I've had much better luck using RunSpace - I use it to pass any powershell commands - here are a snippet from one of the sites and some examples to look at:
'Create the runspace.
Using R As System.Management.Automation.Runspaces.Runspace = _
System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
'Create the pipeline
Using P As System.Management.Automation.Runspaces.Pipeline = R.CreatePipeline()
'Open the runspace.
R.Open()
'Create each command (in this case just one)...
Dim Cmd As New System.Management.Automation.Runspaces.Command("C:\script.ps1", True)
'...and add it to the pipeline.
P.Commands.Add(Cmd)
'Execute the commands and get the response.
Dim Result As System.Collections.ObjectModel.Collection(Of _
System.Management.Automation.PSObject) = P.Invoke()
'Close the runspace.
R.Close()
'Display the result in the console window.
For Each O As System.Management.Automation.PSObject In Result
Console.WriteLine(O.ToString())
Next
End Using
End Using
http://www.winsoft.se/2009/08/execute-a-cmdlet-or-ps1-script-from-visual-basic/
https://social.msdn.microsoft.com/Forums/vstudio/en-US/5d2279c8-e02c-45eb-a631-951c56067bb5/run-powershell-script-from-vbnet?forum=vbgeneral
https://code.msdn.microsoft.com/windowsdesktop/VBPowerShell-6b4f83ea
The last one provides a pretty solid breakdown of what it's doing. Let me know if you can't get it to work, I can try to see if this import works on an app.
I actually found the solution after hours of pain. This is pretty silly solution.
Went I went to my application Properties I found that the Preferred run was set to 32 bit hence when my PowerShell was launched from within it was looking for the module under SYSWOW where its suppose to look it under System32. I unchecked the "Preferred 32 BIT" and not it imports the module from system 32.
Thought I should share this silly miss so that others should not suffer the same.
Alright guys I have a copy of minecraft wich is a java program launched by Minecraft.exe.
Inside the same folder is my program (lets call it launcher.exe) wich I am programming in VB.net and a Folder called LocalAppData.
If I place a shortcut in the same folder as Minecraft.exe, clear the "start in" field and put this in the target field:
C:\Windows\System32\cmd.exe /c start cd LocalAppData&& set APPDATA=%cd%\LocalAppData&& javaw -Xms4096M -Xmx4096M -cp LocalAppData\Minecraft.exe net.minecraft.LauncherFrame
then minecraft launches with my custom memory allocation from inside the LocalAppData folder. Two command windows appear as well. One closes when minecraft does, but the other does not and needs to be closed by the user
My Question is: How do I acheive the same result in VB.net instead of with a windows shortcut and is there a way to either stop the command windows appearing or setting them both to close automatically?
My goal is to launch minecraft from a subfolder, so local filepaths would be far preferrable to global filepaths, but figuring out the location of the application at runtime and working from a subfolder would be ok as well.
I thought I would be able to use the same code inside a Shell() command to produce the same effect, but it appears not.
Ideally I want to create a program that runs minecraft with:
Custom memory allocation
Local filepaths so that it can be run portably
The appdata folder changed to the subfolder so that it can be run portably
Those command windows either gone or minimised and then close automatically when minecraft is closed by the user.
I know this is a big ask, but I'm 6 months into a programming course and I'll admit that I'm not the best programmer out there.
Once I know how to do this I can create the rest of the program that manages multiple installations in seperate subfolders and lets you choose wich one to launch, but I just need help with the actual launching of the java application itself.
Note:
I should clarify that Minecraft.exe is not something that I have made and that I don't program java. I'm just looking for a solution in VB.Net.
Thank you for reading all this and sorry for the long post.
Edit
Thank you for the help. This is what I have so far, but it produces an error "Error: Could not create the JavaVirtualMachine. Error: A fatal exception has occurred. Program will exit"
'Declare Processes
Dim appDataStartInfo As ProcessStartInfo = New ProcessStartInfo()
Dim javaStartInfo As ProcessStartInfo = New ProcessStartInfo()
Dim appPath As String = Application.StartupPath()
'Launch appdata relocation process
appDataStartInfo.FileName = "cmd.exe"
appDataStartInfo.Arguments = "/c start cd " & appPath & "&& set APPDATA=" & appPath & "\LocalAppData"
appDataStartInfo.UseShellExecute = True
Process.Start(appDataStartInfo)
'Launch Minecraft
javaStartInfo.FileName = "javaw.exe"
javaStartInfo.Arguments = "-Xms4096M -Xmx4096M -cp " & appPath & "\LocalAppData\.minecraft\bin\Minecraft.jar net.minecraft.LauncherFrame"
javaStartInfo.UseShellExecute = True
Process.Start(javaStartInfo)
Does anyone see where I've gone wrong?
The Process class (http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx )allows you to launch a process. You set it up with a ProcessStartInfo instance (http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.80).aspx ).
I don't have the time to give you all the details, but this pseudo-code should get you started :
Dim startInfo As ProcessStartInfo = new ProcessStartInfo()
startInfo.FileName = "javaw.exe" 'That's the name of your executable
startInfo.Arguments = "your argument line"
startInfo.UseShellExecute = true 'Needed to open a command window
Process.Start(startInfo)
In vb.net 2008 I want to execute a batch file that resides on another computer.
There is no error, but nothing happens.
Here is the code:
Dim pStart As New System.Diagnostics.Process
Dim startInfo As New System.Diagnostics.ProcessStartInfo(serverpath & "\file.bat")
startInfo.RedirectStandardOutput = True
startInfo.WindowStyle = ProcessWindowStyle.Hidden
startInfo.UseShellExecute = False
pStart = System.Diagnostics.Process.Start(startInfo)
pStart.WaitForExit()
pStart.Close()
To run a process on a remote computer you can use Sysinternals free psexec.
You can call it with the proper parameters and having the required permissions like you are doing in your sample code.
I've never tried to create a Process using a batch file as the executable. I've always had to use cmd.exe as the program. This has worked for me in the past:
Dim startInfo As New System.Diagnostics.ProcessStartInfo("cmd.exe", "/c " & serverpath & "\file.bat")
The "/c" as part of the argument list tells cmd.exe to exit after the batch file has completed.
If you are going to use RedirectStandardOutput, you really do want to use RedirectStandardError, and then also subscribe to the events of the Process class for catching data on those streams (OutputDataReceived and ErrorDataReceived). Otherwise you will have no way to debug your batch script.
This reads like a permissions problem. I would troubleshoot it that way if you haven't ruled it out yet.
Have you tried running the same batch file from the local computer?
If it is a permissions issue you can solve it either copying the file locally before executing it or map a drive to the remote computer where the file is and then execute the batch file from the new path.
Additionally, we don't really know what's in the batch file that could be causing an issue. I would either post the batch file or if you can't post the batch file use a batch file that you can post. Example a batch file would write the current date time to a file.