Add_Event and Remove_Event Methods

Using PowerShell v5.1

 

For capturing the standard error of a process, the following works as I expected.

$Process = [System.Diagnostics.Process]::New()
$Process.StartInfo.CreateNoWindow = $True
$Process.StartInfo.FileName = 'sort.exe'
$Process.StartInfo.Arguments = 'afilenamethatdoesnotexist'
$Process.StartInfo.UseShellExecute = $False
$Process.StartInfo.RedirectStandardError = $True

$StandardErrorEventHandler = {
    if (-not [System.String]::IsNullOrEmpty($EventArgs.Data)) {
        $Event.MessageData.AppendLine($EventArgs.Data)
    }
}

$StandardErrorStringBuilder = [System.Text.StringBuilder]::New()

$StandardErrorEvent = Register-ObjectEvent `
    -InputObject $Process `
    -EventName 'ErrorDataReceived' `
    -Action $StandardErrorEventHandler `
    -MessageData $StandardErrorStringBuilder

[System.Void]$Process.Start()
$Process.BeginErrorReadLine()
$Process.WaitForExit()

Unregister-Event -SourceIdentifier $StandardErrorEvent.Name
$Process.Close()

$StandardError = $StandardErrorStringBuilder.ToString().Trim()
Write-Host $StandardError

 

Result:

afilenamethatdoesnotexistThe system cannot find the file specified.

 

How can I achieve the same result using the ‘Add_Event’ and ‘Remove_Event’ methods instead of using the ‘Register-ObjectEvent’ and ‘Unregister-Event’ cmdlets?

In this case, the method calls would look something like: $Process.Add_ErrorDataReceived( ? ) and $Process.Remove_ErrorDataReceived( ? )

 

Thank you for your time.

The System.Diagnotics.Process object does not have .Add() or .Remove() methods. You could code those methods and add them to the object if you wanted that functionality.

C:\> $Process = [System.Diagnostics.Process]::New()

C:\> $Process | Get-Member -MemberType Method


   TypeName: System.Diagnostics.Process

Name                      MemberType Definition                                                      
----                      ---------- ----------                                                      
BeginErrorReadLine        Method     void BeginErrorReadLine()                                       
BeginOutputReadLine       Method     void BeginOutputReadLine()                                      
CancelErrorRead           Method     void CancelErrorRead()                                          
CancelOutputRead          Method     void CancelOutputRead()                                         
Close                     Method     void Close()                                                    
CloseMainWindow           Method     bool CloseMainWindow()                                          
CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType) 
Dispose                   Method     void Dispose(), void IDisposable.Dispose()                      
Equals                    Method     bool Equals(System.Object obj)                                  
GetHashCode               Method     int GetHashCode()                                               
GetLifetimeService        Method     System.Object GetLifetimeService()                              
GetType                   Method     type GetType()                                                  
InitializeLifetimeService Method     System.Object InitializeLifetimeService()                       
Kill                      Method     void Kill()                                                     
Refresh                   Method     void Refresh()                                                  
Start                     Method     bool Start()                                                    
ToString                  Method     string ToString()                                               
WaitForExit               Method     bool WaitForExit(int milliseconds), void WaitForExit()          
WaitForInputIdle          Method     bool WaitForInputIdle(int milliseconds), bool WaitForInputIdle()

Thank you Logan.

My apologies. I meant to refer to the Add_Event and Remove_Event event accessors.

I’m trying to replicate their use as shown here: https://stackoverflow.com/a/42033478

The following does not work. PowerShell will hang for about four seconds before closing. The PowerShell ISE will close, then restart with a warning that it did not close normally.

$Process = [System.Diagnostics.Process]::New()
$Process.StartInfo.FileName = 'sort.exe'
$Process.StartInfo.Arguments = 'afilenamethatdoesnotexist'
$Process.StartInfo.UseShellExecute = $False
$Process.StartInfo.RedirectStandardError = $True

$ErrorHandler = {Write-Host "Inside the error handler."} -as $Process.PSObject.Members.Match('ErrorDataReceived')[0].Value.EventHandlerType

$Process.Add_ErrorDataReceived($ErrorHandler)

[System.Void]$Process.Start()
$Process.BeginErrorReadLine()
$Process.WaitForExit()

$Process.Remove_ErrorDataReceived($ErrorHandler)

$Process.Close()

 

The following works. I would like to understand why the previous example does not.

$Process = [System.Diagnostics.Process]::New()
$Process.StartInfo.FileName = 'sort.exe'
$Process.StartInfo.Arguments = 'afilenamethatdoesnotexist'
$Process.StartInfo.UseShellExecute = $False
$Process.StartInfo.RedirectStandardError = $True

$ErrorHandler = {Write-Host "Inside the error handler."}

$ErrorEvent = Register-ObjectEvent `
    -InputObject $Process `
    -EventName 'ErrorDataReceived' `
    -Action $ErrorHandler

[System.Void]$Process.Start()
$Process.BeginErrorReadLine()
$Process.WaitForExit()

Unregister-Event -SourceIdentifier $ErrorEvent.Name

$Process.Close()

Thank you for your time.