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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With