I am attempting to use the updated technique omegastripes provides here to crate a helper script for silently launching PowerShell and getting results/status back. The first thing I did was refactor to help me understand the logic. Basically I got rid of the two functions, one with a forced exit, and moved them into an If/Then/Else. I also moved all everything into the Conditional when searching for the identified window. So I went from this:
Dim strCmd, strRes, objWnd, objParent, strSignature
If WScript.Arguments.Named.Exists("signature") Then WshShellExecCmd
strCmd = "%comspec% /c tasklist"
RunCScriptHidden
WScript.Echo strRes
Sub RunCScriptHidden()
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
End Sub
Sub WshShellExecCmd()
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()
WScript.Quit
End Sub
To this:
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
Set objParent = objWnd.getProperty(WScript.Arguments.Named("signature"))
objWnd.Quit
objParent.strRes = CreateObject("WScript.Shell").Exec(objParent.strCmd).StdOut.ReadAll()
Exit For
End If
Next
Else
strCmd = "%comspec% /c tasklist"
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
That works great, and my only question there is just a critique of the refactor. Is there anything that could be improved, and indeed, is there any argument against the refactor in the first place?
From there, I revised the strCmd
to
strCmd = "powershell.exe -noLogo -noProfile -executionPolicy bypass -file ""\\Mac\Px\Support\Px Tools\Dev 3.3.#\_Spikes\TestMessage.ps1"" -message:""It's ALIVE!"""
Which calls this PowerShell
param (
[string]$message
)
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $null
[System.Windows.Forms.MessageBox]::Show($message) > $null
So far, so good. Now to get status back from the PowerShell. And here I should be clear, the ultimate goal is a generic launcher where I want to be able to catch any errors, pass them back to the VBS, and from there write to an error log or event. Some of the potential errors include things like passing a parameter that doesn't exist in the target PS1. So, getting back to returning info, I have tried:
Write-Output "Write-Output"
Write-Host "Write-Host"
Out-Host "Out-Host"
None of these actually gets returned. So, how can I output to Standard Output such that the VBS can access that info? I THINK one aspect is that the original strCmd emits Standard output as it processes, whereas PowerShell is going to output at the end. But that's just a guess at the issue, so rather than cluttering this with more experiments I will ask, is this possible, and if so, what changes are needed?