Expert Solution for 2011 Scripting Games Beginner Event 10: Use Easy PowerShell Code to Time Script Operations

Expert Solution for 2011 Scripting Games Beginner Event 10: Use Easy PowerShell Code to Time Script Operations

  • Comments 5
  • Likes

Summary: Microsoft PowerShell MVP Marco Shaw solves beginner event 10 in the 2011 Scripting Games and shows how to time script operations

Microsoft Scripting Guy, Ed Wilson, here. Marco Shaw is the author of the expert commentary for Beginner Event 10.

Photo of Marco Shaw

Marco is a consultant with CGI in Moncton. He has been working in the IT industry for over 12 years, also working for Bell Aliant and Atlantic Lottery. He was awarded the Microsoft MVP award for his contributions to the Windows PowerShell community in 2007, 2008, 2009, and 2010. His recent authoring activities have included writing Windows PowerShell content for a Windows Server 2008 book published by Microsoft Press and writing a Windows PowerShell-related article on System Center Operations Manager 2007 for TechNet Magazine. He also provided Windows PowerShell content for a SQL Server 2008 book by SAMs publishing company and for a just released revised edition of System Center Operations Manager 2007 Unleashed by SAMs. He also coauthored the 2nd edition of PowerShell Unleashed published by SAMs, which was released early in 2009. He has spoken at Microsoft TechDays in Halifax, Canada the last two years where he has delivered sessions on System Center Operations Manager 2007 R2, Windows Server 2008 R2, and Windows PowerShell.

Worked solution

My task was to write a solution for Beginner Event 10. Based on my IT-related work experience, I always make sure that I have a decent grasp of the requirements before I start any kind of solution to a problem or question. I love to ask questions, sometimes to the chagrin of others (but I did well in a short meeting at work today).

I thoroughly read the problem and the desired output and extra points. Then I read it again, and because this only takes 60 seconds of my, sometimes-uneventful life, I read it again!

All right, after those three minutes of reading, I need to fire up my Windows PowerShell ISE.

Thinking about the desired output, I think New-TimeSpan is the only cmdlet that can output values in milliseconds. I have to check this out:

new-timespan get-date (get-date).addseconds(5)

That outputs an error—how about wrapping the values to compare sothey are evaluated properly?

new-timespan (get-date) ((get-date).addseconds(5))

I always forget that with Compare-Object also. That works!

Remembering the bonus points, this approach will allow me to easily add a variable for the 5. I also want to set up a simple variable to set the number of runs, which I should be able to easily use with the start_number…end_number syntax.

I know the Measure-Object cmdlet also has an average parameter switch. Enough thinking, my head is starting to hurt. Let's try this out.

1..5|foreach{new-timespan (get-date) ((get-date).addseconds(5))|select -exp totalmilliseconds}|measure-object -average

I’m sticking with a one-liner for the time being.

OK, that doesn't seem to provide the same level of exactness as the sample code, but the problem doesn't define what it should be either (and there are no bonus points for that either). I'm not going to overcomplicate a solution when it isn't a requirement or other incentive.

One final change to display only the average:

$avg=1..5|foreach{new-timespan (get-date) ((get-date).addseconds(5))|select -exp totalmilliseconds}|measure-object -average|select -expand average

It’s getting longer.

Now, when it comes to output, I prefer to write a simple string with variables to the console, but let's make this one a bit more PowerShell-y...

Now I never remember how to use the -f format operator, so off to Bing.com I go...

OK, here's what I have coded in the ISE:

$tries=5

$seconds=5

$avg=1..$tries|foreach-object{

  new-timespan (get-date) ((get-date).addseconds($seconds))|select-object -expand totalmilliseconds

}|measure-object -average|select-object -expand average

"Average time of {0} runs of {1} seconds is {2} milliseconds" -f $tries,$seconds,$avg

Trying to stick with a one-liner for $avg makes it a bit harder to read. I always indent my code with two spaces. That’s just a personal thing though…some like using a tab.

It works!

Thank you for your solution, Marco.

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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Dear Marco.

    I really do like you! And I read a lot of your articles especially the VB.Net ones!

    But:

    I solved event 5 and you said: you read it several times!

    OK! But not very likely!

    This is the first solution where I really don't understand the least little bit of it!

    The event says:

    Use "Start-Sleep" five times and measure the average time! ... in short and simplified!

    What your solution does: It calculates the timespan between Now and Now+5 seconds

    The result is calculated in "no time", of course!

    It should last 25 seconds to iterate through Start-Sleep 5 --- five times!

    And you don't measure the time it takes to execute a scriptblock ( generalized )

    This is no solution to event 10!

    Sorry ... but no stars!

    kind regards, Klaus

  • @Klaus

    Wow...  You're 100% right.  It appears I didn't follow the article at all from my proposed solution.  I re-read the event, and completely missed it from the base requirements.  I don't use Start-Sleep at all...

    So, my solution does deserve a 0.

    Marco

  • Dear Marco,

    thank you so much for all your superb articles, books and blogs ...

    BUT: Today ... erverything else doesn't count ... our soccer club

    just won the german championship 2011 !!!

    hope to meet you next year @ sg2012, Marco!

    Kind regards, Klaus

  • An alternative to this could be something like this:

    Function Measure-CommandTime

    {

       Param (

           [int]$repeat = 5,

           [int]$seconds = 5

       )

       PROCESS

       {

           $result = 0

           # Command

           $Command = (Measure-Command -Expression {Start-Sleep -Seconds $seconds}).TotalMilliseconds

           # Run command for given repeats

           for ($i = 0; $i -lt $repeat; $i++)

           {

               $result = $result + $command

           }

           # Results

           "Average time of {0} runs of {1} seconds is {2} milliseconds" -f $repeat,$seconds,($result/$repeat)

       }

    }

    Measure-CommandTime -repeat 5 -seconds 5

  • thank you