Console Application output is not shown - vb.net

I have read several questions in StackOverflow about redirecting output/errors
from application but It could not help me.
I have developed an executable in C# code. It recovers software from system registry
and call a webservice to save it to our database.
Inside the executable we are printing messages with
Console.WriteLine("Message from Executable");
On the other hand we have a CRM application and I have written two win forms
that call psexec.exe with the desired parameters and this .exe is remotely
copied and launched on target machine.
If you use direct psexec call with that parameters in cmd.exe, we can see the psexec
execution banners and OUR executable output
Something like:
PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010
Mark Russinovich Sysinternals - www.sysinternals.com
Enterprise software # 2012
Message from application
Starting task in machine "XXXXXXX"
Recovering software list from registry
Program.exe exited on MACHINE with error code 0.
When I make the psexec call with .NET, I cant recover my application output, It
just shows:
PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010
Mark Russinovich Sysinternals - www.sysinternals.com
Program.exe exited on MACHINE with error code 0.
I am assigning to Process class a delegate who is recovering async
data from process, but this information, is not there.
I paste some code to see If you can find the reason my C# Console application
output does not appear:
The command I launch is:
Dim CmdExe As String = "\\#MAQUINA# -u #USUARIO# -p #CLAVE# -s -c -f """ + executionPath + """"
Parametes -s (Run as system) -c (Copy local file to remote system) -f (force overwrite)
Private Sub LanzarProceso()
CheckForIllegalCrossThreadCalls = False
Dim Proceso As New Process
AddHandler Proceso.OutputDataReceived, AddressOf CallbackProcesoAsync
AddHandler Proceso.ErrorDataReceived, AddressOf ErrorDataReceivedAsync
Dim startInfo As New ProcessStartInfo
startInfo.FileName = execFile
startInfo.Arguments = CmdExe.Replace("#MAQUINA#", txtFiltroMaquina.Text).Replace _
("#USUARIO#", txtUsuario.Text.Trim).Replace _
("#CLAVE#", txtClave.Text.Trim)
Proceso.EnableRaisingEvents = True
startInfo.UseShellExecute = False
startInfo.RedirectStandardOutput = True
startInfo.RedirectStandardError = True
startInfo.CreateNoWindow = False
Proceso.StartInfo = startInfo
Proceso.Start()
Proceso.BeginOutputReadLine()
Proceso.BeginErrorReadLine()
Proceso.WaitForExit()
End Sub
Delegates handling data:
Private Sub CallbackProcesoAsync(sender As Object, args As System.Diagnostics.DataReceivedEventArgs)
If Not args.Data Is Nothing AndAlso Not String.IsNullOrEmpty(args.Data) Then
If Not listtask.InvokeRequired Then
listtask.Items.Add(args.Data.ToString)
Else
Dim d As New TextToControl(AddressOf AddToControl)
listtask.Invoke(d, args.Data.ToString)
End If
End If
End Sub
Private Sub ErrorDataReceivedAsync(sender As Object, args As System.Diagnostics.DataReceivedEventArgs)
If Not args.Data Is Nothing AndAlso Not String.IsNullOrEmpty(args.Data) Then
If Not listtask.InvokeRequired Then
listtask.Items.Add(args.Data.ToString)
Else
Dim d As New TextToControl(AddressOf AddToControl)
listtask.Invoke(d, args.Data.ToString)
End If
End If
End Sub
I checked the program is finishing correctly. THe c# executable has
Enviroment.Exit(0);
at the end of the execution

Ok, the best workaround I found to get all the output between psexec and my c# application
after execution is:
Dim CmdExe As String ="\#MAQUINA# -u #USUARIO# -p #CLAVE# -s -c
-f """ + executionPath + """ > outputFileCode.txt"
This allow me to parse the standard output without having to change anything or calling
my program directly, because I can`t do it.

What you see in the console window is a mix of output sent to console by both psexec as well as the child process. You can intercept the output from psexec, but to do the same for the child would require the interception code in the psexec, which apparently it does not have
Try to remove the intermediary - call your executable directly

Related

TF.exe doesn't prompt for checkin confirmation when executed directly, without using the operating system shell to start the process

I'm using TF.exe command-line for some simple TFS commands such as getting the latest version of the files (tf.exe vc get), checking out some files (tf.exe vc checkout) and then checking them in at the end of use (tf.exe vc checkin).
After some tests I've noticed that when I run the checkin command through Windows Command Prompt (cmd.exe), the prompt window is displayed asking for confirmation before the check-in command is done:
C:\Program Files\Microsoft Visual Studio\2022\Community
\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer>
tf.exe vc checkin "C:\TfsTestProject\test.txt" /comment:"Checked via command-line."
For my project that was a good thing, displaying the prompt window for check-in confirmation.
However, when I started the TF command through code I found a problem: I have to start the TF.exe process redirecting the standard output, so I can display what's happening when the command is executed, and for that I have to set process.StartInfo.UseShellExecute = False. But when I do that, the prompt window is no longer displayed, as if I was using the /noprompt parameter (and I'm not using it).
So, when I use the code below the prompt window is stil displayed, as in the picture, but I cannot receive the standard output stream feedback:
Dim p = New Process()
' I removed the full path for clarity, but that's:
' "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
p.StartInfo.FileName = "TF.exe"
p.StartInfo.Arguments = $"vc checkin ""{testFilePath}"" /comment:""Checked via code."""
p.StartInfo.UseShellExecute = True
p.StartInfo.CreateNoWindow = True
p.Start()
p.WaitForExit()
But, when I use this other code, the one that I need, the prompt window for check-in confirmation is no longer displayed, even though I'm not using /noprompt parameter:
Dim p = New Process()
' I removed the full path for clarity, but that's:
' "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
p.StartInfo.FileName = "TF.exe"
p.StartInfo.Arguments = $"vc checkin ""{testFilePath}"" /comment:""Checked via code."""
p.StartInfo.UseShellExecute = False ' <- That's the problem, apparently.
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.CreateNoWindow = True
p.EnableRaisingEvents = True
AddHandler p.OutputDataReceived, Sub(s, e) Console.WriteLine(e.Data)
p.Start()
p.BeginOutputReadLine()
p.WaitForExit()
I couldn't find any information about that behaviour, maybe it's just a bug?
Shame on me, I've done some research before posting the question and found nothing, but, just after posting it I found this:
c# - How can I capture tf.exe stderr without stopping its dialog prompts? - Stack Overflow
This problem is old, since that question is from 10 years ago, facing the same "bug". Apparently there is an undocumented parameter /prompt that makes the prompt window to be displayed even though the TF command is not executed through shell.
So this code (with undocumented /prompt parameter) worked:
Dim p = New Process()
' I removed the full path for clarity, but that's:
' "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
p.StartInfo.FileName = "TF.exe"
' With undocumented /prompt parameter the prompt window is
' displayed even when the command is not executed through shell.
p.StartInfo.Arguments = $"vc checkin ""{testFilePath}"" /prompt /comment:""Checked via code."""
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.CreateNoWindow = True
p.EnableRaisingEvents = True
AddHandler p.OutputDataReceived, Sub(s, e) Console.WriteLine(e.Data)
p.Start()
p.BeginOutputReadLine()
p.WaitForExit()
And after that question and answer from long time ago I've tested a little more and found that I was wrong, the problem is not about not starting the command from shell, the problem really happens when the streams (output or error) are redirected. When you just set UseShellExecute = False, without redirecting, the prompt window is still displayed.

git is not recognized when running a batch job in Visual Basic application

I have a VB app that I want to pull down a repo upon a button click.
Upon button click, my project runs a .cmd file (Frontend.cmd) that I have saved in my project resources folder:
cd ..
cd ..
cd Users\Username\Documents
git clone https://gitusername:token#github.com/repofilepath.git
PAUSE
Running Frontend.cmd normally works without issue, the repo is pulled down successfully. However, when running the .cmd file through the VB application, I get the git is not recognized error.
'git' is not recognized as an internal or external command,
operable program or batch file.
I have added C:\Program Files\Git\bin\ and C:\Program Files\Git\cmd\ paths as suggested in this answer:
'git' is not recognized as an internal or external command
Is there another path I must add?
Here is my button click code if needed:
Dim output As String
output = My.Resources.Frontend
Dim programPath As String = Path.GetTempPath & “\” & program & ".cmd"
Using sw As StreamWriter = New StreamWriter(programPath)
sw.Write(output)
End Using
If (My.Computer.FileSystem.FileExists(programPath)) Then
Dim procStartInfo As New ProcessStartInfo
Dim procExecuting As New Process
With procStartInfo
.UseShellExecute = True
.FileName = programPath
.WindowStyle = ProcessWindowStyle.Normal 'use .hide to hide the process window
.Verb = "runas" 'run as admin
End With
MsgBox("Please press Yes when system ask permissions", MsgBoxStyle.Information, "myProgram")
procExecuting = Process.Start(procStartInfo)
End If

Writing to Command Line Not Working

An application I need to use (USB capture utility) has a .cmd version that I can call from my Visual Basic code. I am able to launch the application and put it in "command line mode" like this:
Public Class MyClass
Dim StreamWriteUtility As System.IO.StreamWriter
Dim StreamReadUtility As System.IO.StringReader
Dim ProcessInfo As ProcessStartInfo
Dim Process As Process
Public Sub StartUSBCapture(ByVal DataStorageLocation As String)
Dim ProcessInfo As ProcessStartInfo
Dim Process As New Process
ProcessInfo = New ProcessStartInfo("C:\FW_Qualification_Suite\data-center-windows\data-center\bin\datacenter.cmd", "-c ")
ProcessInfo.CreateNoWindow = True
ProcessInfo.UseShellExecute = False 'Must be changed if redirect set to True
ProcessInfo.RedirectStandardInput = True
Process = Process.Start(ProcessInfo)
SWUtility = Process.StandardInput
While True
SWUtility.WriteLine("run") 'Looping for test to ensure this isn't a timing issue
End While
End Sub
End Class
This launches the application and opens a separate command line window that should accept further commands (i.e., capture, run, stop, etc). However, I am having trouble getting those subsequent commands to show up in the command line window. I've tried redirecting the standard input of the process, but still nothing shows up in the console window.
Can anyone tell how I'm supposed to actually get these commands from my Visual Basic program into this application?

Console App / Task Scheduler

I have a console app written in VB Net that works perfectly. Now I want to run it using task scheduler. The problem is that the app has a console.readline command at the very end that keeps the console window open until the user hits enter. Is there a way to test whether the app is running in a session or not?
If I knew that the app was not tied to a desktop console, I would not write the comments to the console and I'd bypass the final console.readline command.
You should add an argument to your task to indicate it is unattended. For example, pass /u in your scheduled task. Check for /u in your program to determine if it should skip the console.readline.
excerpt from msdn forum
Dim args() As String = Environment.GetCommandLineArgs()
' args(0) = Full path of executing program with program name
' args(1) = First switch in command - /u
if args(1) = "/u" then ....
Or you can change the signature of your Main() to Public Sub Main(ByVal args() As String) and you won't need to use Dim args() As String = Environment.GetCommandLineArgs()

Running CMD command on windows service

I have created a windows service that requires executing an EXE file with the CMD process. I have used the following code:
Str = "C:\PCounter\Staff\account.exe CHARGE " & Name & " " & Amount & " TO" & Id
Dim procStartInfo As New System.Diagnostics.ProcessStartInfo(Str)
procStartInfo.RedirectStandardOutput = True
procStartInfo.UseShellExecute = False
procStartInfo.CreateNoWindow = True
Dim proc As New System.Diagnostics.Process
proc.StartInfo = procStartInfo
proc.Start()
proc.Dispose()
However the above code will return
system cannot find the file specified
I have tried same code on the Windows form, and its works fine. To make sure the path is correct I have added a text file in the same location as EXE file, and load the content of the text file in the service. It works fine.
I can't think of anything else; I really would appreciate it if you can help me on this.
ProcessStartInfo has two properties. One for the executable to run, and the other for the arguments to pass to the executable. The symantics for the Arguments property are the exact same as the command line.
You can not include the arguments in the same property as the executable. They must be separated.
Create service:
sc create Vm-Symantec04 binPath= "\"C:\App32\VMware\VMware Workstation\vmrun.exe\" -T ws start \"D:\VM\Sym04\Sym04.vmx\" nogui" depend= "VMAuthdService/VMnetDHCP/VMUSBArbService/VMware NAT Service" start= auto
Delete service:
sc delete Vm-Symantec04