System.Diagnostics.Process for STDOUT/STDERR

Started by spl, April 07, 2024, 05:32:53 AM

Previous topic - Next topic

spl

This is a quickie follow-up from Tony's code on the recent thread for slack.exe. The .NET System.Diagnostics.Process has a lot to offer. I wanted to see how it might help with capturing STDOUT/STDERR from  command... I realize here are earlier udfs (I think Detlev published one of the first)... so the code below may or may not be a better mousetrap, but it worked and was cool to write as investigating .NET is a useful keep-yer-skills-sharp
;simple demo to obtain STDOUT/STDERR via CLR
;Stan Littlefield 4/7/2024
;==========================================================
cmd = "ping.exe"
args = "-n 1 localhost"
ObjectClrOption("useany","System")
objInfo = ObjectClrNew("System.Diagnostics.ProcessStartInfo")
Output=""
objInfo.FileName = cmd
objInfo.RedirectStandardError = ObjectType("BOOL",@TRUE)
objInfo.RedirectStandardOutput = ObjectType("BOOL",@TRUE)
objInfo.UseShellExecute = ObjectType("BOOL",@FALSE)
objInfo.Arguments = args
oProcess = ObjectClrNew("System.Diagnostics.Process")
oProcess.StartInfo = objInfo
oProcess.Start()
oProcess.WaitForExit()
STDOUT = oProcess.StandardOutput.ReadToEnd()
STDERR = oProcess.StandardError.ReadToEnd()
Output = Output:"Command ":cmd:" ":args:@CRLF
Output = Output:"STDOUT: ":STDOUT:@CRLF
Output = Output:"STDERR: ":STDERR:@CRLF
Message("CLR Process",Output)
Exit
Stan - formerly stanl [ex-Pundit]

spl

Placed the CLR stuff into a udf. The examples are related Python but should be applicable to PHP command line or .js files.
Code (WINBATCH) Select
;simple demo to obtain STDOUT/STDERR via CLR
;Stan Littlefield 4/7/2024
;==========================================================
Gosub udfs
;2 examples / comment,uncommnet to test
cmd="py" ;will run Python if it is installed
args='-m pip show pywin32'
msg="Is Pywin32 Installed"

;args='-c "import sys; print(sys.exec_prefix)"'
;msg="Python Path"

Display(2,"Running...",cmd:" ":args)
vals = Get_stdout()
Message(msg,vals)
Exit
;==========================================================
:udfs
#DefineSubroutine Get_stdout()
ObjectClrOption("useany","System")
objInfo = ObjectClrNew("System.Diagnostics.ProcessStartInfo")
Output=""
objInfo.FileName = cmd
objInfo.RedirectStandardError = ObjectType("BOOL",@TRUE)
objInfo.RedirectStandardOutput = ObjectType("BOOL",@TRUE)
objInfo.UseShellExecute = ObjectType("BOOL",@FALSE)
objInfo.Arguments = args
oProcess = ObjectClrNew("System.Diagnostics.Process")
oProcess.StartInfo = objInfo
oProcess.Start()
oProcess.WaitForExit()
STDOUT = oProcess.StandardOutput.ReadToEnd()
STDERR = oProcess.StandardError.ReadToEnd()
Output = Output:STDOUT:@CRLF
If STDERR<>""
   Output = Output:"STDERR:":STDERR:@CRLF
Endif
oProcess = 0
objInfo = 0
Return (Output)
#EndSubroutine
Return
;==========================================================

Stan - formerly stanl [ex-Pundit]

spl

The udf for STDOUT may also be useful searching for text. Below calls a PS one-liner to quickly return results. I wanted to query my script repository for files that contained the SaveAs() method and it was fun to see the PS code could quickly return results via WB.
;simple demo to obtain STDOUT/STDERR via CLR
;Stan Littlefield 4/14/2024
;==========================================================
Gosub udfs
;Powershell Example
path = "c:\scripts\*.wbt"
pattern = "SaveAS"
cmd="Powershell"
args= 'Get-ChildItem -Path ':path:' -recurse |  Select-String -Pattern "':pattern:'" ;Exit'
msg="Search SaveAS() in WB code"

Display(2,"Running...",cmd:" ":args)
vals = Get_stdout()
Message(msg,vals)
Exit
;==========================================================
:udfs
#DefineSubroutine Get_stdout()
ObjectClrOption("useany","System")
objInfo = ObjectClrNew("System.Diagnostics.ProcessStartInfo")
Output=""
objInfo.FileName = cmd
objInfo.RedirectStandardError = ObjectType("BOOL",@TRUE)
objInfo.RedirectStandardOutput = ObjectType("BOOL",@TRUE)
objInfo.UseShellExecute = ObjectType("BOOL",@FALSE)
objInfo.Arguments = args
oProcess = ObjectClrNew("System.Diagnostics.Process")
oProcess.StartInfo = objInfo
oProcess.Start()
oProcess.WaitForExit()
STDOUT = oProcess.StandardOutput.ReadToEnd()
STDERR = oProcess.StandardError.ReadToEnd()
Output = Output:STDOUT:@CRLF
If STDERR<>""
   Output = Output:"STDERR:":STDERR:@CRLF
Endif
oProcess = 0
objInfo = 0
Return (Output)
#EndSubroutine
Return
;==========================================================
Stan - formerly stanl [ex-Pundit]

spl

and while on the PS STDOut, employing the pipeline can make for interesting one-liners. For example running Get_stdout() with this
cmd="Powershell"
args= "Get-ScheduledTask | where state -eq 'Disabled' | Select-Object TaskPath,Taskname,State | ConvertTo-Csv -NoTypeInformation"
msg="Disabled Scheduled Tasks"

I got this
Stan - formerly stanl [ex-Pundit]

cssyphus


spl

Quote from: cssyphus on April 15, 2024, 10:45:04 AMThis is great stuff. Thanks Stan.

Appreciate that. Little irony with last Taskbar Operation. Most PC's win10-11 and possibly Win7 come preset with PS version 5.1. But Powershell 7 is available and the command is PWSH, not Powershell. In 5.1 the Converto-Csv cmdlet will enclose all columns with quotes regardless. PS 7 added a new parameter -UseQuotes AsNeeded which is really cool. However, PS 7 does not respect a command-line argument with a pipeline. But it does respect generating a .ps1 file with the command line... so if one were to use PS 7 and include the new parameter something like this will succeed.
pscode = "Get-ScheduledTask | where state -eq 'Disabled' | Select-Object TaskPath,Taskname,State | ConvertTo-Csv -UseQuotes AsNeeded -NoTypeInformation"
file="c:\temp\pstest.ps1"
If FileExist(file) Then FileDelete(file)
Fileput(file,pscode)
cmd="PWSH"
args=file
msg="Disabled Scheduled Tasks"

NOTE: very difficult to upload even a small jpeg without several edits.
Stan - formerly stanl [ex-Pundit]