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
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
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
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.
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
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
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).
- Oisin