Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Does anyone understand how to use Event forwarding

36 views
Skip to first unread message

Bob Landau

unread,
Mar 10, 2009, 8:22:01 PM3/10/09
to
This is the blog that I'm working from

http://blogs.msdn.com/powershell/archive/2008/06/11/powershell-eventing-quickstart.aspx

The specific section is Lee's topic on Event Forwarding/Support Events.

soapbox on
Microsoft if you are listening PLEASE do not use the generic "args[x]"
parameter for describing function/script parameters. While this is great for
read-once/run-many scripts; by definition everything you write is read-many.
soapbox off

Here is my question there are two functions and what looks to me like one
script level call that is used to wire everything up. Trouble is there is no
example on how to call this script which looks to me is meant to be
dot-sourced. Here are the two functions that I've believe I proto-typed
correctly to more easily demonstrate what I don't understand.

I'm guessing that both functions are Event handlers that have the following
siguatures based on how $args is used within these functions.

function Enable-ProcessCreationEvent([object] $source, [PSEventArgs] $e)
function Disable-ProcessCreationEvent([object] $source, [PSEventArgs] $e)

i.e. Enable-ProcessCreationEvent

Register-ObjectEvent -InputObject $processWatcher -EventName
"EventArrived" -SupportEvent 'WMI.ProcessCreated' -Action {
[void] (New-Event -SourceIdentifier "PowerShell.ProcessCreated"
-Sender $args[0] -EventArguments
$args[1].SourceEventArgs.NewEvent.TargetInstance)
^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Where in this specific example $args[1] is the EventArrivedEventArgs
parameter for [System.Management.ManagementEventWatcher]::EventArrived

What I don't understand is how at the script level I "glue" these two event
handlers with the script level call to Register-EngineEvent which is (updated
for CTP3)

## Register for the custom "PowerShell.ProcessCreated" engine event
Register-EngineEvent -SourceIdentifier "PowerShell.ProcessCreated" -Action {
$processName = $args[1].SourceArgs[0].Name.Split(".")[0]
(New-Object -COM Sapi.SPVoice).Speak("Welcome to $processName")


First the PSEngineEvent class doesn't look to have a ProcessCreate

http://msdn.microsoft.com/en-us/library/system.management.automation.psengineevent_members(VS.85).aspx

Second and I am assuming that it must (have this event) how can does the
Register-EngineEvent tie process creation to the two above script level
functions.

Or perhaps most simply just how to you get this code to work?

thx
bob

PaulChavez

unread,
Mar 11, 2009, 1:36:01 AM3/11/09
to
The key is the -Action parameter to Register-ObjectEvent. In this example Lee
uses that parameter to pass in a script block which fires a custom PowerShell
engine event names "Powershell.ProcessCreated" using the New-Event cmdlet.

The example is basically subscribing to a WMI event via
Register-ObjectEvent, then forwarding that event on inside a PSEngineEvent
which he then subscribes to via Register-EngineEvent.

Hope that helps,
Paul

Bob Landau

unread,
Mar 11, 2009, 11:51:01 AM3/11/09
to
Paul,

Sorry for being a little dense this morning I can't get this to work two
questions.

1) What should I be passing on the command line Enable-ProcessCreationEvent?
It takes two parameters

2) What are you passing to the script when its invoked. It needs the
$args[1] parameter to pass into the script level call to
Register-EventEngine.

Here is what I am seeing and the reason for my post

If I don't register the Powershell.ProcessCreated event and just call
Enable-ProcessCreationEvent without passing any parameters; the event is
queued. I don't believe it should since the -Action clause is being used to
process the event.

but

If I run the script "as is"; Register-EngineEvent gets called and creates a
subscriber for the event Prowershell.ProcessCreated. Now when I invoke
Enable_PorcessCreationEvent no event gets queued which is expected but I
don't here "Welcome to notepad" when I start Notepad from the same shell that
was wired to get these events

I am able to instanciate the Sapi.SPVoice and the Speak method will talk to
me if I call it directly.

PaulChavez

unread,
Mar 11, 2009, 12:50:01 PM3/11/09
to
OK, I got it to work and now I think I can clear things up.

First off to answer your two questions, the $args parameter is *not* the
same as what you are thinking. None of these functions takes a parameter. The
$args variable in this example refers to the property of SourceArgs on the
event you are subscribing to. It is used within the -action scriptblock only.

The main issue with this example was that as Lee warned on the post, the
$args parameter has changed. Also, the cmdlet names have changed.

Here's a summary of the changes that needed to be made, and then the updated
version below.

* You no longer have to reference the SourceArgs property of $args
* New-PSEvent is now New-Event
* Unregister-PSEvent is now Unregister-Event
* Register-PSEvent is now Register-EngineEvent

BTW, I got this working in CTP3.

## Enable process creation events
function Enable-ProcessCreationEvent
{
$query = New-Object System.Management.WqlEventQuery
"__InstanceCreationEvent", `
(New-Object TimeSpan 0,0,1), `
"TargetInstance isa 'Win32_Process'"
$processWatcher = New-Object System.Management.ManagementEventWatcher
$query

$identifier = "WMI.ProcessCreated"
Register-ObjectEvent $processWatcher "EventArrived" -SupportEvent
$identifier -Action {
[void] (New-Event "PowerShell.ProcessCreated" -Sender $args[0]
-EventArguments $args[1].NewEvent.TargetInstance)
}
}

## Disable process creation events
function Disable-ProcessCreationEvent
{
Unregister-Event -Force -SourceIdentifier "WMI.ProcessCreated"
}

## Register for the custom "PowerShell.ProcessCreated" engine event

Register-EngineEvent "PowerShell.ProcessCreated" -Action {
$processName = $args[0].Name.Split(".")[0]


(New-Object -COM Sapi.SPVoice).Speak("Welcome to $processName")
}

## Eventually
Unregister-Event PowerShell.ProcessCreated

Bob Landau

unread,
Mar 11, 2009, 3:13:20 PM3/11/09
to
Thanks for clearing up my confusion. You were absolutely correct I was not
associating $args with the action scriptblock.

For the curious the type which is currently passed into the "Action" block
of Register-EngineEvent is a "ManagementBaseObject" which is used to wrap a
WMI class. In this case the class is "Win32_Process" so you have access to
all the properties such as "Name". I guess this shouldn't in hindsight be
surprising since the WMI query is filtering on Win32_Process.

The types that are passed into Register-ObjectEvent are
ManagementEventWatcher and EventArrivedEventArgs respectively

I know have a much better understanding on how to wire these up; thanks to
Paul. I do hope that will be better documentation on how these Eventing api's
fit together as well as a guideline on what "args" represent in these action
blocks.

bob

Oisin G.

unread,
Mar 16, 2009, 3:21:29 PM3/16/09
to
On Mar 11, 3:13 pm, Bob Landau <BobLan...@discussions.microsoft.com>
wrote:
> > > Register-EventEngine.- Hide quoted text -
>
> - Show quoted text -

If you want to have a closer look at what is available inside the -
Action scriptblock, try this:

# register a handler for a synthetic non .net/object event
ps> Register-EngineEvent -Source MyEvent -Action
{ $host.enternestedprompt() }

# raise the event
ps> New-Event -Source MyEvent > $null

# you are now inside the event handler in an interactive context
+ps> dir variable: | more

"exit" when done. CTP3 may crash. This is not exactly production level
hacking ;-)

Here is an old script of mine for CTP2 that may illuminate some of the
forwarding concepts a bit better (you'll have to fix up the event
cmdlet names - e.g. new-psevent -> new-event etc).

http://www.nivot.org/2008/08/16/AutoMountunmountNewPSDrivesForRemovableDrivesAndNetworkSharesInPowerShellV2.aspx

- Oisin


0 new messages