Display output of the CMD in real time inside TextBox

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
This topic is 5 years and 6 months old and has exceeded the time allowed for comments. Please begin a new topic or use the search feature to find a similar but newer topic.
Locked
jvierra
Posts: 15439
Last visit: Tue Nov 21, 2023 6:37 pm
Answers: 30
Has voted: 4 times
Been upvoted: 33 times

Re: Display output of the CMD in real time inside TextBox

Post by jvierra »

Here is how to make a full async read work in a form.
Attachments
Demo-Capture StandardOutAsync.psf
(17.2 KiB) Downloaded 261 times
User avatar
davidc
Posts: 5913
Last visit: Mon Jul 08, 2019 8:55 am
Been upvoted: 2 times

Re: Display output of the CMD in real time inside TextBox

Post by davidc »

If you don't set the $process.SynchronizingObject property, it will crash PowerShell. That was the issue I was having before.
David
SAPIEN Technologies, Inc.
jvierra
Posts: 15439
Last visit: Tue Nov 21, 2023 6:37 pm
Answers: 30
Has voted: 4 times
Been upvoted: 33 times

Re: Display output of the CMD in real time inside TextBox

Post by jvierra »

The exception is being missed by the scriptdriver. PowerShell CLI also misses the exception.
Faulting application name: scriptdriver64.exe, version: 1.4.48.0, time stamp: 0x5ae7594d
Faulting module name: KERNELBASE.dll, version: 10.0.17134.165, time stamp: 0xb0bb231d
Exception code: 0xe0434352
Fault offset: 0x000000000003a388
Faulting process id: 0x4dd0
Faulting application start time: 0x01d42f48f7837a64
Faulting application path: C:\Program Files (x86)\Common Files\SAPIEN Debugger 2018\scriptdriver64.exe
Faulting module path: C:\WINDOWS\System32\KERNELBASE.dll
Report Id: bd3e6bcf-7744-4b97-b1a6-c5b9b50365ce
Faulting package full name:
Faulting package-relative application ID:
User avatar
ALIENQuake
Posts: 112
Last visit: Mon Jan 29, 2024 7:35 am
Has voted: 4 times

Re: Display output of the CMD in real time inside TextBox

Post by ALIENQuake »

Guys that looks amazing, let me digg into it and post back :shock:
User avatar
ALIENQuake
Posts: 112
Last visit: Mon Jan 29, 2024 7:35 am
Has voted: 4 times

Re: Display output of the CMD in real time inside TextBox

Post by ALIENQuake »

I did it! Now I con not only display progress in real time but also send input if application suddenly ask for it! I'm using:

Code: Select all

$buttonSendInput_Click={
	$process.StandardInput.WriteLine($textboxInput.Text)
}
and it works. I didn't know much about process.EnableRaisingEvents and $process.SynchronizingObject so thank you for you help.
User avatar
davidc
Posts: 5913
Last visit: Mon Jul 08, 2019 8:55 am
Been upvoted: 2 times

Re: Display output of the CMD in real time inside TextBox

Post by davidc »

FYI, I plan to will integrate this into the Process Tracker Control Set in an upcoming service build.
David
SAPIEN Technologies, Inc.
User avatar
ALIENQuake
Posts: 112
Last visit: Mon Jan 29, 2024 7:35 am
Has voted: 4 times

Re: Display output of the CMD in real time inside TextBox

Post by ALIENQuake »

davidc Thanks!

Do you think that it can solve yet another challenge? It's possible to wait for process exit?
Because I have two or more process, I want to execute them one by one (and at the same time, display output of the CMD in real time inside TextBox) and the next process has to wait for another because otherwise, it can't access/modify files in use. Sequence of the execution matters.

I can't use waitForExit() because it stops receiving output (works as design I think). Possible to achieve via extra Process Tracker or too good to be true?
I try to set $global:Monit = $true and wait for it to be false but usage of while of any kind [System.Threading.Thread]::Sleep(1000) is also preventing output/hang application.

Maybe I need to create new form for each process? Or add condition when there is no more OutputDataReceived ?
Last edited by ALIENQuake on Sat Sep 01, 2018 4:09 am, edited 1 time in total.
jvierra
Posts: 15439
Last visit: Tue Nov 21, 2023 6:37 pm
Answers: 30
Has voted: 4 times
Been upvoted: 33 times

Re: Display output of the CMD in real time inside TextBox

Post by jvierra »

You can use WMI to get an async notification of a process exit.
jvierra
Posts: 15439
Last visit: Tue Nov 21, 2023 6:37 pm
Answers: 30
Has voted: 4 times
Been upvoted: 33 times

Re: Display output of the CMD in real time inside TextBox

Post by jvierra »

The following can also be done in PowerShell:
  1. static Task<int> RunProcessAsync(string fileName){
  2.     var tcs = new TaskCompletionSource<int>();
  3.  
  4.     var process = new Process {
  5.         StartInfo = { FileName = fileName }, EnableRaisingEvents = true
  6.     };
  7.  
  8.     process.Exited += (sender, args) => {
  9.         tcs.SetResult(process.ExitCode);
  10.         process.Dispose();
  11.     };
  12.  
  13.     process.Start();
  14.  
  15.     return tcs.Task;
  16. }
User avatar
ALIENQuake
Posts: 112
Last visit: Mon Jan 29, 2024 7:35 am
Has voted: 4 times

Re: Display output of the CMD in real time inside TextBox

Post by ALIENQuake »

jvierra wrote: Fri Aug 31, 2018 3:37 pm You can use WMI to get an async notification of a process exit.
This is what I've manage to create:

Code: Select all


$formAsyncPingerTest_Load = {
	
	$pstart = 'SELECT * FROM Win32_ProcessStartTrace'
	$pstop = 'SELECT * FROM Win32_ProcessStopTrace'
	
	$action = {
		$nevent = $Event.SourceEventArgs.NewEvent
		if ($nevent.ProcessName -eq 'ping.exe' -and $Event.SourceIdentifier -eq 'Process.Stop') {
			$global:processExited = $true
		}
		if ($nevent.ProcessName -eq 'nslookup.exe' -and $Event.SourceIdentifier -eq 'Process.Stop') {
			$global:processExited = $true
		}
	}
	Register-WmiEvent -Query $pstart -SourceIdentifier 'Process.Start' -Action $action
	Register-WmiEvent -Query $pstop -SourceIdentifier 'Process.Stop' -Action $action

}
$global:process_OutputReceived = {
	$global:processExited = $false
	$textbox1.Lines += $_.Data
	$textbox1.Select($textbox1.Text.Length, 0)
	$textbox1.ScrollToCaret()
}
$global:process_Exited = {
	$global:processExited = $true
	Write-Host 'Exited'
	Write-Host $global:processExited
	}

$buttonPing_Click = {


	'ping', 'ping' | % {
		
		$script:process = New-Object System.Diagnostics.Process
		$process.EnableRaisingEvents = $true
		$process.StartInfo.RedirectStandardError = $true
		$process.StartInfo.RedirectStandardOutput = $true
		$process.StartInfo.RedirectStandardInput = $true
		$process.StartInfo.FileName = $_
		$process.StartInfo.RedirectStandardOutput = $true
		$process.StartInfo.UseShellExecute = $false
		$process.StartInfo.CreateNoWindow = $true
		$process.StartInfo.Arguments = '-n 5 google.com'
		$process.add_OutputDataReceived($process_OutputReceived)
		$process.add_Exited($process_Exited)
		$process.SynchronizingObject = $formAsyncPingerTest
		
		$global:processExited = $false
		
		$process.Start() | Out-Null

		$process.BeginOutputReadLine()

		while ($global:processExited -eq $false) {
			[System.Threading.Thread]::Sleep(1000)
			Write-Host $global:processExited
		}
	}
	
}

$buttonStop_Click={
	#TODO: Place custom script here
	$process.CancelOutputRead()
	$process.Kill()
	$process.Dispose()
}

$formAsyncPingerTest_FormClosed=[System.Windows.Forms.FormClosedEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.FormClosedEventArgs]
	#TODO: Place custom script here
	$process.CancelOutputRead()
	$process.Kill()
	$process.Dispose()
	Get-EventSubscriber | Unregister-Event -Force
}
1. One button, two process names from array, each should be executed
2. at the start of the process, $global:processExited = $false
3. while $global:processExited = $false, wait before dealing with next object from array <-- this is where it hangs application
4. if OutputReceived , set $global:processExited = $false
5. if process_Exited, set $global:processExited = $true so while loop can continue

In theory, it should work but it hangs whole app and it doesn't display output in textbox. Without 'while' both process are executed at once. How to achieve this concept without using 'while'/blocking BeginOutputReadLine() ?
The following can also be done in PowerShell:
The c# static Task<int> RunProcessAsync code from you post is too complicated, maybe I will find powershell version of it but does it will suit my concept from above?
This topic is 5 years and 6 months old and has exceeded the time allowed for comments. Please begin a new topic or use the search feature to find a similar but newer topic.
Locked