Weekend Scripter: Playing with PowerShell Processes and Events


Summary: Microsoft Scripting Guy, Ed Wilson, talks about playing with processes and events in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. This morning I woke up and I had an idea. This happens to me sometimes. Not often. But occasionally. And here it was. I could not get it out of my mind...

Can I use an event from a specific process? I wonder. I should be able to do this, but hmmmm. I know a process that I retrieve by using the Get-Process cmdlet is really an instance of System.Diagnostics.Process. I also know that in addition to having methods and properties, it has events. Here are the events I get when I look at a specific process:

PS C:\> Get-Process notepad | Get-Member -MemberType Event

   TypeName: System.Diagnostics.Process

Name               MemberType Definition

----               ---------- ----------

Disposed           Event      System.EventHandler Disposed(System.Object, System.Event...

ErrorDataReceived  Event      System.Diagnostics.DataReceivedEventHandler ErrorDataRec...

Exited             Event      System.EventHandler Exited(System.Object, System.EventArgs)

OutputDataReceived Event      System.Diagnostics.DataReceivedEventHandler OutputDataRe...

Without getting all froggy and looking stuff up in MSDN, I figure that I have a pretty good idea of what an Exited event might really be—it is an event that is raised when a particular process exits.

Let me try the Windows PowerShell console

I decided to launch Notepad, and then use the Get-Process cmdlet to retrieve that instance of Notepad. Now I use the Register-ObjectEvent cmdlet, supply the Process object as an InputObject, and I specify that I want to monitor for the Exited event. In the action portion, I start Notepad, and I unregister the event subscriber.

I press ENTER, and I wait.

I close Notepad…

And I wait.

And I wait.

And I wait.

Nothing happens. Bummer.

I press ENTER in the Windows PowerShell console, and suddenly Notepad reappears. Hmmm…I wonder if this is an STA/MTA kind of thing. I launch Windows PowerShell in MTA mode (powershell –mta) and in STA mode (powershell –sta). Still nothing. It only works after I press ENTER. Bummer. Not such a good deal at this point. By the way, here is a screenshot:

Image of command output

One of the nice things about using the Register-ObjectEvent cmdlet is that it does not require me to launch an elevated Windows PowerShell console (or ISE). This is great because I seldom launch Windows PowerShell with elevated permission. Most of the time, I try things without elevation.

What about the ISE?

I open the Windows PowerShell ISE and type my script:

Start-Process notepad

$n = Get-Process notepad

$job = Register-ObjectEvent -InputObject $n -EventName exited -SourceIdentifier notepad -Action {

    Start-Process notepad

    Get-EventSubscriber | Unregister-Event }

When I run the script, Notepad appears. Cool. I close Notepad, and it immediately reappears. Cool. If I close that instance of Notepad, however, Notepad remains closed. This is due to the fact that I am monitoring a specific instance of Notepad, and once I close that particular instance of Notepad, the new instance is a different process. Therefore, I cannot call the object event from that new process because I have not captured it in the $n variable.

Advantages?

Using Register-ObjectEvent seems to have the following advantages for me:

  • Does not automatically require admin rights
  • Syntax is easier
  • Really fast
  • Lower overhead

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Comments (3)

  1. jrv says:

    @Ed

    The following works in PowerShell CLI in both STA and MTA mode. It avoids the extra carriage return required wheb you try and paste you version of the code.

    [System.Threading.Thread]::CurrentThread.ApartmentState

    $n=Start-Process notepad -PassThru
    $sb={
    Write-Host ‘Event called’ -fore green
    Start-Process notepad
    Get-EventSubscriber | Unregister-Event
    }

    $job=Register-ObjectEvent -InputObject $n -EventName exited -SourceIdentifier notepad -Action $sb

  2. jrv says:

    The following works in PowerShell CLI in both STA and MTA mode. It avoids the extra carriage return required wheb you try and paste you version of the code.

    [System.Threading.Thread]::CurrentThread.ApartmentState

    $n=Start-Process notepad -PassThru
    $sb={
    Write-Host ‘Event called’ -fore green
    Start-Process notepad
    Get-EventSubscriber | Unregister-Event
    }

    $job=Register-ObjectEvent -InputObject $n -EventName exited -SourceIdentifier notepad -Action $sb

  3. JV says:

    The following works in PowerShell CLI in both STA and MTA mode. It avoids the extra carriage return required wheb you try and paste you version of the code.

    [System.Threading.Thread]::CurrentThread.ApartmentState

    $n=Start-Process notepad -PassThru
    $sb={
    Write-Host ‘Event called’ -fore green
    Start-Process notepad
    Get-EventSubscriber | Unregister-Event
    }

    $job=Register-ObjectEvent -InputObject $n -EventName exited -SourceIdentifier notepad -Action $sb

Skip to main content