Microsoft Subnet An independent Microsoft community View more

Fun with PowerShell 2.0 Eventing!

As promised, this posting is the first of hopefully several that will talk about PSH 2.0 features.  Hmmm... in fact, maybe I will turn this into an ongoing series named "Stupid PowerShell Tricks".

Anyhow, Eventing was one of the things that kind of thwarted me with the CTP2 build.  For some reason, I just could not get Eventing to work correctly (well actually not at all).  That being said, thanks to a brain dump from the product team, me realizing that my logic was flawed, and the CTP3 version, I can not only get Eventing work (well kinda).  But, I felt that I might be able to help other people as well.  So... the following is a step-by-step which hopefully shows how to use Eventing with a custom assembly.

BTW - CTP3 was just released.  Click here for more!

Step One

Load up your custom assembly, create an object, and see if the object supports Events.  For example the following shows how you might do this using some pseudo code:

Add-Type -Path "C:\tools\SuperCool.dll"

$MyObject = New-Object cool.scp "host1", "myuser", "mypassword"

$MyObject | Get-Member

In my case, the resulting formatted table had the following events:

  • OnTransferEnd
  • OnTransferProgress
  • OnTransferStart

Cool, considering I was transferring files between systems.

Step Two

Once you have figured out which types of events are available to you, using those events is the next challenge.  To figure that out, use the Register-ObjectEvent cmdlet to register an event subscription into your PowerShell session.  For example:

Register-ObjectEvent  -InputObject $MyObject -EventName OnTransferProgress -SourceIdentifier Scp.OnTransferProgress `

      -Action {$Global:MCDPtotalBytes = $args[3]; $Global:MCDPtransferredBytes = $args[2]}

Register-ObjectEvent  -InputObject $MyObject -EventName OnTransferEnd `

      -SourceIdentifier Scp.OnTransferEnd -Action {$Global:MCDPGetDone = $True}

So... what exactly is going on here...  First off, you are using the InputObject parameter to pass in your object to the cmdlet.  You are doing this because the cmdlet needs the object from which it will create the event subscription.  For the EventName name parameter, you provide the name of the event(s) you discovered in step one.  For the SourceIdentifier parameter, you just need to provide a unique name.  I tend to use something that is related to the object from which my events will be coming from.  Lastly, the Action parameter is optional.  In my case, I needed the event to do something.

At this point, you might be asking, "Just how is Tyson using these events?"

Well, at first, I just needed the script to wait until a command that was issued was done moving a file using SCP.  Basically, without the script waiting, it kept going once a Get or Put command was issued.  If I was interactively issuing these commands, that would have been fine.  But, because the script was getting, comparing, and then copying files all from the remote source.  I was running into timing issues were the script was trying to compare files that had yet not finishing copying.

To make the script wait, I had two options.  First, I could use the Wait-Event cmdlet, which will cause the script to wait for a particular event to occur.  Unfortunately when I used this cmdlet, I kept running into strange issues were the script execution sometimes didn't "Wait" or just kept "Waiting".  It turned out the waiting issue was related to stuff like network drops, which resulted in the event never being fired.  While the other issue remains a mystery.

At any rate, the second option was put together a loop that just kept checking for something to be True.  For this we first start with the scriptblock that was defined for one of the action parameters I listed previous:

-Action {$Global:MCDPGetDone = $True}

Note to the wise, the scriptblock defined for the action parameter executes within its own scope.  Hence, why I define the MCDPGetDone variable as Global!

Next, we define the following loop:

do {Write-Progress -Activity "Getting - $($_.Name)" -Status "Copying" -PercentComplete (($MCDPtransferredBytes/$MCDPtotalBytes)*100)} while ($MCDPGetDone -eq $Null)

Super cool... not only does my now script wait for a file to be transferred!  But, thanks to the OnTransferProgress event handler I also get a progress bar.  :>)

Hopefully this was helpful!

If you like this, check out some other posts from Tyson:

Or if you want, you can also check out some of Tyson's latest publications:

Lastly, visit the Microsoft Subnet for more news, blogs, and opinions from around the Internet.  Or, sign up for the bi-weekly Microsoft newsletter(Click on News/Microsoft News Alert)

Join the Network World communities on Facebook and LinkedIn to comment on topics that are top of mind.
Must read: 10 new UI features coming to Windows 10