Shell.Execute in VBA is not doing anything - vba

I am trying to use powershell to extract some files from a zip folder located on a drive where I only have read access to my desktop in a temp folder where I can do whatever I like to them.
Using the code below I get no errors but the powershell code just does nothing.
Am I missing something?
Sub unzip_test()
Dim myshell As Shell32.Shell
Set myshell = New Shell32.Shell
Dim args As String
args = "Expand-Archive -LiteralPath " & "'C:\Users\user1\Desktop\TEMP\examplezip.zip'" & " -destinationpath " & "'C:\Users\user1\Desktop\TEMP\tester'"
'Debug.Print (args)
myshell.ShellExecute "powershell", vargs:=args
End Sub
The debug.print prints Expand-Archive -LiteralPath 'C:\Users\user1\Desktop\TEMP\examplezip.zip' -destinationpath 'C:\Users\st11524\Desktop\TEMP\tester'
Also, I have "Microsoft Shell Controls and Automation" checked in my references.

It should work. I think the problem is somewhere in the Expand-Archive call, but you can't see the answer.
The quick fix is to add -NoExit to your call, like this
args = "-NoExit Expand-Archive -LiteralPath " ...
This will allow you to read the error before it closes, but you can't read it from your code. If you need that, have a look here

After testing this on another computer I've come to the conclusion that this is a permissions thing. My personal computer runs the script just fine where my work computer won't. I don't see anything wrong with the code listed above so I will consider this issue resolved.

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"""

VBA - Execute or Run .bat File Inside Macro

I have been attempting to automate a series of administrative events for some of the users where I work by creating scripts and macro's and so on..
These scripts and macros work great, however, I would like to make a the process even easier for the users by running a single batch file that will systematically execute the scripts and macros.
The batch file I currently have, calls all the scripts one by one, and the very last script opens one of the xlsm workbooks which contains a few macro's in it - and here is where the issue is - There are still scripts to be executed but they can only be executed once this workbook has executed all its macros.
So my initial thought was to test if the workbook is open, if it is, delay the execution of the next script by a minute or so, then test again and again... until it is closed.. Then I thought perhaps it would be easier to execute the next set of scripts (also in a batch file) from within a macro.
So, I have this code:
Sub Run_BAT()
Set obj = CreateObject("Wscript.Shell")
obj.Run Chr(34) & "X:\Test\" & "Termination Reports Scripts\" & "Execute_Terminations.bat" & Chr(34), 0, True
Set obj = Nothing
End Sub
Which gives me an error:
Permission Denied
Then there's this code:
Sub WriteAndRunBatFile()
Call Shell("X:\Test\Termination Reports Scripts\Execute_Terminations.bat")
End Sub
Which gives me the error:
Invalid procedure call
Any and every single code sample that contains the "Shell" command gives this error.
Place your path to bat file in quotes:
Call Shell("cmd /c ""S:/somebatfile.bat""", vbNormalFocus)
Or
Call Shell("cmd.exe /C /K " & "ChDir X:\Test\Termination_Reports_Scripts && Execute_Terminations.bat", vbNormalFocus)
And yes, check permissions.
My theory is you're missing a reference in your application to the Windows Script Host Object Model.
In the VBA Editor, go to Tools, References, make sure that one's ticked.
It's not ticked by default for security reasons - imagine unintended access to the command prompt in every instance of a Microsoft Office application...!
(1) Check permission of user of that X directory.
(2) Test the code by removing spaces from directory name.
Also try the following code (Please try it by removing spaces from directory name).
Sub Button1_Click()
Call Shell("CMD.EXE /C " & "X:\Test\Termination_Reports_Scripts\Execute_Terminations.bat")
End Sub

Import-Module not working from within WinForms Application

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.

CMD file executed from VBA leads to different results

PROBLEM IS SOLVED ALREADY
this should be fairly simple, but I can't figure out what's wrong.
I have a cmd file in V:\something\XYZ.cmd, which takes 1 parameter.
When I execute it manually, e.g. Windows-Explorer and double-click the cmd, I get my result.
Now I have a XLSM file on my Desktop and a macro should invoke this cmd instead.
Problem is, when executed that way, I get some "file-not-found errors" in the cmd itself.
So how could I simulate the manual execution of the cmd.
There must be some path related problem...
This is how I execute from VBA:
Call Shell("cmd.exe /c " & "V:\something\XYZ.cmd" & " " & someParameter, vbNormalFocus)
I tried to put a
ChDir "V:\something\"
right before the call, but that doesn't change anything...
Where's the problem?
thank you, I just found the error myself:
There was a %root% used inside the script, this was the error. Changed it to absolute path, now it works

Possibility of VB.net and VBScript

Is it possible to include in a VB.net 2008 Project a VBScript (test.vbs) and run it if its while the processing necessary? But the main thing is it should be possible to BUILD just one .exe.
If so, can you also receive values / arguments from the VBS file?
Here is an example, although it's pointless, but it is used for unterstanding:
VB.net -> exe is running
the exe runs please_find_the_coputername.vbs
The script please_find_the_coputername.vbs -> obtained the computer name and sends this variable to VB.net
VB.Net displays the computer name via Msgbox().
Note: I know that I can read out the computer name with VB.net but this example is only for understanding my questions.
Edit:
HI #maxedev thank you for your answer.
Wow.. its nice trick.
But I want only to do this VBScript code in VB.net:
Dim strComputer
strComputer = "LP-BKR"
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
Set colComputer = objWMIService.ExecQuery ("Select * from Win32_ComputerSystem")
For Each objComputer in colComputer
Wscript.Echo "Logged-on Domain: " & objComputer.Domain
Wscript.Echo "Logged-on UserName: " & objComputer.UserName
Wscript.Echo "Logged-on ComputerName: " & objComputer.Name
Next
set objWMIService = Nothing
set colComputer = Nothing
I searched the whole day to get the same Value... but didn't find anything. That's why I decide to do that in this way. But if I think, the trick with clipboard is risky. It pushes the still clipboard text away. How can I realize it?
I'm not sure exactly what you're trying to accomplish, but you could write to a text file and then read it through vb.net - or you could do something like this post to use the clipboard to pass info ie :
VBS:
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "cmd.exe /c echo hello world | clip", 0, TRUE
VB.NET:
MessageBox.Show(Clipboard.GetText)
--shows "hello world"
One solution would be to add a reference to the MS Script Control:
http://msdn.microsoft.com/en-us/library/aa227400(v=vs.60).aspx
Using that, you can add literally add code (VBScript) with the AddCode() method then run it and get the output back. I have a tiny example here.
Windows automatically provides the information you're looking for in environment variables:
%USERNAME% -> username of the logged in user
%USERDOMAIN% -> WINS name of the domain the user is logged into
%USERDNSDOMAIN% -> FQDN of the domain the user is logged into
%COMPUTERNAME% -> hostname of the computer