Link to home
Start Free TrialLog in
Avatar of ROM
ROMFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Get output from Powershell commands in VB or VBA.

Hey All,

How can I get the output from the following commands please.

562       Set wsh = New WshShell
         
572       strCom = Chr(34) & _
                 "C:\Apps\PSCodeRunner\RunCode.cmd" & _
                 Chr(34)
582       lngErrorCode = wsh.Run(strCom, _
                           WindowStyle:=0, _
                           WaitOnReturn:=True)

I have a powershell being executed in that file as follows:

C:\windows\sysnative\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command "cd \; [console]::Title='RC PS Processor'; [IntPtr]::Size; c:\apps\PSCodeRunner\PSScript.ps1; Exit"


I have tried piping in clip such as | clip but the only kind of output I get is:

WARNING: The names of some imported commands from the module 'tmp_hsh4edta.1jr' include unapproved verbs that might
make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the
Verbose parameter. For a list of approved verbs, type Get-Verb.

ModuleType Version    Name                                ExportedCommands                                            
---------- -------    ----                                ----------------                                            
Script     1.0        tmp_hsh4edta.1jr                    {Add-AvailabilityAddressSpace, Add-DistributionGroupMember...

And what I want is the actual output you get from the PS ISE etc... or PS generally.

Please advise

Many thanks

R
Avatar of Coralon
Coralon
Flag of United States of America image

This doesn't make a lot of sense.. you're using vbscript to kick off powershell that runs a cmd batch file?  

The error you are getting is pretty straightforward.  When you import a command (by module, dot sourcing, etc.) if your functions have a single word name, they won't generate an error, but if powershell sees the - in the name, then your verb has to be from the approved verb list, or you get that error.

Anyway.. back to the original question.  Look at the MSDN documentation for ProcessStartInfo.  You can configure that in your powershell to capture the StdOut, StdErr, etc. https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo?view=netframework-4.7.2
You'll configure the RedirectStandardOutput and RedirectStandardError, set the UseShellExecute to $false in your configuration and go from there.  

Here's an example from one of my old scripts (semi-sanitized)
		
$ProcessInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo
$ProcessInfo.FileName = 'myprogram.exe'
$ProcessInfo.RedirectStandardError = $true
$ProcessInfo.RedirectStandardOutput = $true
$ProcessInfo.UseShellExecute = $false
$ProcessInfo.WindowStyle = 'Hidden'
$ProcessInfo.Arguments = 'Normal command line arguments here'
$Process = New-Object -TypeName System.Diagnostics.Process
$Process.StartInfo = $ProcessInfo
		
$null = $Process.Start()
$Process.WaitForExit()

Open in new window


from there, you can use your $Process.StandardOutput and $Process.StandardError to do whatever you want with them.

Coralon
ASKER CERTIFIED SOLUTION
Avatar of Michael B. Smith
Michael B. Smith
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ROM

ASKER

Thanks everyone

I originally was doing all of this within VBScript in VBA in MSAccess as this is what the application is written in.

However, after lots of testing it was found that VBA in MSAccess will NOT run the 64bit of PowerShell.

So the workaround is getting a file I call from VBA to kick off a new PowerShell command outside of VBA and MSAccess therefore allowing 64bit PowerShell and therefore all my 365 commands work as they were not before.

Hence the setup I need to achieve.

I would prefer to run the other way, however, after a lot of work and testing and help from EE as well.. this is what worked so I could run commands against 365..

So that is where I need to get the results from please.

Thanks

R
Avatar of ROM

ASKER

HI Michael.. however not output I can see please.

Thanks

R
What do you mean? The VBS opens cmd.exe which then executes a PowerShell script and leaves the cmd.exe session open.

To wit:
User generated image
Avatar of ROM

ASKER

Hi Michael,

But I want to take the output into VBA and do something with it in the App

R
I went back and re-read the entire thread. You didn't state that anywhere, just that you wanted to "get the output".

Regardless, it's a simple matter of re-directing the PowerShell output to a temporary file and then opening that file in the VBS. Do you know how to do that?
Avatar of ROM

ASKER

Hi Michael.. I do state the output twice in the Original Question.

Anyway....

I am assuming > c:\filename within the command somewhere? However I tried CLIP and it gave me the above.

Is there something further to do? As I want the results like Powershell NOT the output I had earlier.

Thanks in advance

R

R
Avatar of ROM

ASKER

Could you supply an example please

Thanks

R
Sorry, I had to do some actual work this morning. :-)

Here it is, all nice and neat and pretty.
Option Explicit

Const ForReading   = 1
Const ForWriting   = 2
Const ForAppending = 8

Const TristateUseDefault = -2
Const TristateTrue       = -1
Const TristateFalse      = 0

Sub e (str)
	WScript.Echo str
End Sub

Function ErrorReport (str)
	If Err.Number Then
		ErrorReport = True
		e "Error 0x" & CStr (Hex (Err.Number)) & " occurred " & str
		If Err.Description <> "" Then
	                e "Error description: " & Err.Description & "."
		End If
		Err.Clear
	Else
		ErrorReport = False
	End If
End Function

Function TmpFolder
    Dim temp: temp = oShell.ExpandEnvironmentStrings("%Temp%")
    e "TmpFolder = " & temp
    TmpFolder = temp
End Function

Function TmpFileName
    Dim objRan

    Set objRan = CreateObject("System.Random")
    Dim ran:  ran  = objRan.Next_2( 1, 10000 )
    Set objRan = Nothing

    Dim temp: temp = TmpFolder
    Dim file: file = temp & "\" & ran

    '' file is the name of the file where your PowerShell output is redirected
    e "TmpFileName = " & file

    TmpFileName = file
End Function

Function DummyPowerShellScript
    Dim file, oFile

    file = TmpFolder & "\" & "dummy.ps1"
    e "DummyPowerShellScript = " & file

    Set oFile = oFS.OpenTextFile(file, ForWriting, True, TristateFalse)
    If ErrorReport ("while creating " & file) Then
        WScript.Quit 1
    End If

    oFile.WriteLine "write-host -fore green powershell output"
    oFile.WriteLine "dir"
    oFile.Close
    If ErrorReport ("while closing " & file) Then
        WScript.Quit 1
    End If

    Set oFile = Nothing

    DummyPowerShellScript = file
End Function

Function DummyBatch (psFile, temp)
    Dim file, oFile

    file = TmpFolder & "\" & "dummy.bat"

    Set oFile = oFS.OpenTextFile(file, ForWriting, True, TristateFalse)
    If ErrorReport ("while creating " & file) Then
        WScript.Quit 1
    End If

    oFile.WriteLine "powershell.exe -NoExit -Command " & Chr(34) & _
    "& { " & _
        "[Console]::Title='RC PS Processor'; " & _
        "[IntPtr]::Size; " & _
        psFile & " | Out-File -LiteralPath '" & temp & "' -Encoding ascii; " & _
        "sleep 2; " & _
        "exit; " & _
    "}" & _
    Chr(34)

    oFile.Close
    If ErrorReport ("while closing " & file) Then
        WScript.Quit 1
    End If

    Set oFile = Nothing

    DummyBatch = file
End Function

Sub ReadTmpFile(file)
    Dim objFile, strLine

    WScript.Echo "About to open = " & file

    ''On Error Resume Next

    Set objFile = oFS.OpenTextFile(file, ForReading)
    If ErrorReport ("while opening " & file) Then
        WScript.Quit 1
    End If

    Do While Not objFile.AtEndOfStream
        strLine = objFile.ReadLine()
        '' Do something with strLine
        e "strLine = " & strLine
    Loop

    objFile.Close
    If ErrorReport ("while closing " & file) Then
        WScript.Quit 1
    End If

    Set objFile = Nothing
End Sub

Sub Wait (sec)
    Dim temp

    temp = Timer
    Do While Timer-temp<sec
    Loop
End Sub

    ''
    '' Main
    ''

    ''On Error Resume Next

    Dim oShell, oFS
    Dim temp, file, psFile

    Set oShell = WScript.CreateObject("WScript.Shell") 
    If ErrorReport ("while creating WScript.Shell") Then
        WScript.Quit 1
    End If

    Set oFS = CreateObject("Scripting.FileSystemObject")
    If ErrorReport ("while creating Scripting.FileSystemObject") Then
        WScript.Quit 1
    End If

    psFile = DummyPowerShellScript
    temp   = TmpFileName

    file   = DummyBatch(psFile, temp)

    '' use /k if you want the cmd.exe session to hang around
    ''oShell.Run "cmd.exe /k " & file
    oShell.Run "cmd.exe /c " & file

    Wait 1
    ReadTmpFile(temp)

    Set oFS    = Nothing
    Set oShell = Nothing

Open in new window

Avatar of ROM

ASKER

@Coralon

Could you explain a little more about the error message please and approved verbs.

So I understand please.

Thanks

R
Microsoft only "approves" specific verbs.  If a verb is unapproved, then anytime you use that cmdlet, it will throw warning messages that the verb is unapproved.  It doesn't actually *stop* anything.. but it's ugly, and for production level scripts, it's not something you want hanging around.  (The old PowerCLI module had some cmdlets with unapproved verbs).  

Your error message said that one of the exported commands from the module tmp_hsh4edta.1jr had an unapproved verb.    You can use Get-Verb to see the list of approved verbs.   For your module, I would run a get-command -module tmp_hsh4edta.1jr to see which command has the unapproved verb.  

The other piece to this is if your command is a single word.. like TestSomething, it will *not* throw that unapproved warning message.  My guess is that it is because it is not in the verb-noun format as expected (although personally, I'd think that it should throw a warning about the  cmdlet construction being incorrect, but that's just me :-)

Coralon
The warning message the OP got is from importing the Exchange module.

As @Coralon wrote, it's just a warning. And the OP can suppress it. Not likely they are going to update Exchange. :-)
Avatar of ROM

ASKER

LOL... not updating correct :).

I think this is because I had a clobber command.

Removed now.

WIll continue to test in the development.

WIll feedback, thanks

R
Good to know that the Exchange modules have a "bad" cmdlet name in them.  Glad the MS doesn't even follow their own standards.. lol..
Over 600 Exchange cmdlets were written before PowerShell 1.0 was released. The standards didn't exist - at that time they were "guidelines" and even PowerShell itself didn't follow all the guidelines. (This was when Exchange 2007 was in beta and PowerShell at the time was called "Monad".)
Avatar of ROM

ASKER

Thanks Michael.

This is now in production ;)

R