Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hidden PS window via VBS with return code

I am trying to use a VBScript helper script to launch a PowerShell script in a hidden window. I have been doing this successfully for some time, but now I want to add getting a return code, and that makes things more complicated. The usual approach for getting a return code is to use .Exec rather than .Run, but then you lose the ability to hide the command window. I found this thread, and based on that and a known working strCMD, I tried

strCMD = strCMD & " > c:\out.txt"
objShell.Run strCMD, 0, True

But that doesn't work. Any suggestions where I am going wrong? Or suggestions on a better way to get a hidden Powershell script with return code? FWIW, I have to target PS 2.0. :(

For completeness, the value of strCMD is

powershell -noLogo -noProfile -file "C:\Program Files\PragmaticPraxis\Resources\TestMessage.ps1" -message:"I'M ALIVE!!!" -message2:"Me too!"

And TestMessage.ps1 is simply

[CmdletBinding()]
param (
    [string]$message,
    [string]$message2
)

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $null
[System.Windows.Forms.MessageBox]::Show($message)
[System.Windows.Forms.MessageBox]::Show($message2)

EDIT: Thanks to omegastripes' link, I am trying to implement a more general and PowerShell focused version of this implementation, with some code refactor to eliminate the one time calls to functions and awkward forced exits. What I have is this:

Option Explicit
Dim strCmd, strRes, objWnd, objParent, strSignature

If WScript.Arguments.Named.Exists("signature") Then 
    For Each objWnd In CreateObject("Shell.Application").Windows
        If IsObject(objWnd.getProperty(WScript.Arguments.Named("signature"))) Then Exit For
    Next
    Set objParent = objWnd.getProperty(WScript.Arguments.Named("signature"))

    objWnd.Quit
    objParent.strRes = CreateObject("WScript.Shell").Exec(objParent.strCmd).StdOut.ReadAll()
Else
    strCmd = "powershell.exe -noLogo -noProfile -executionPolicy bypass -file ""\\Mac\Px\Support\Px Tools\Dev 3.3.#\_Spikes\TestMessage.ps1"""
    strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
    GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty strSignature, Me
    CreateObject("WScript.Shell").Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0, True

    WScript.Echo strRes
End If

Which in turn calls this PS1

try {
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $null
    [System.Windows.Forms.MessageBox]::Show("Message test!") > $null
    Write-Host "Success"
} catch {
    Write-Host "Failure"
}

This works in that it does run the PS1, and it is hidden, but I am having trouble getting results back. I have tried Return, Write-Output and Write-Host and none sends the results from the PS1 back to the VBS. I am also having some issues when passing arguments, and I really don't like the For Each loop with a forced Exit internally, but that is polish. The bigger issue is how to consistently get results back from the PS1.

like image 752
Gordon Avatar asked Nov 18 '22 08:11

Gordon


1 Answers

Your powershell script needs to return an exit code through

Exit <int>

Your WScript.Shell's Run method in VBS will then return this code so you need to save it.

Set WshShell = WScript.CreateObject("WScript.Shell")
Result = WshShell.Run(...

So Result now contains the Exit code so you can now either use it or return it again and exit the process.

WScript.Quit(Result)
like image 131
Ultimate Luki Avatar answered Dec 05 '22 07:12

Ultimate Luki