Average Rating:

5.00 by 2 users.

51 Downloads, 202 Views

2 Comment(s)

beginner 10

By: Chris Seiter 21 Apr 2011 08:56 PM UTC in the category: Beginner Event 10

Description:

report back average time a command was run for a specified number of times.
<#
	.SYNOPSIS
		This powershell will determine the average time for a command to run multiple times.

	.DESCRIPTION
		Beginner 10 4-19-2011
		This script will loop through a command multiple times to determine it's estimated average
		time to completion.  Default values are start-sleep -seconds 5 run 5 times.  Extra points
		for variables to allow for other scenarios, clean code, and formatting output.
		
	.PARAMETER CommandString
		the command string that is to be timed; required to be enclosed in curly brackets {}

	.PARAMETER Iterations
		the number of times the command is to be run to get an average

	.EXAMPLE
		beginner10.ps1
		This will run the default command the default number of times and return the average

	.EXAMPLE
		beginner10.ps1 -cs commandtotest
		This will run the specified command the default number of times and return the average.

	.EXAMPLE
		beginner10.ps1 -it numberofruns
		This will run the default command the specified number of times and return the average.
		
	.EXAMPLE
		beginner10.ps1 -cs commandtotest -it numberofruns
		This will run the specified command the chosen times and return the average.

	.EXAMPLE
		beginner10.ps1 | format-table days|hours|minutes|seconds|milliseconds|iterations|command
		Run the command and report back a table with the chosen objects reported.

	.EXAMPLE
		beginner10.ps1 -detail yes
		This will show the averages along with a detailed report of each time counter for each iteration.
		The detailed report is non-customizable, however.

	.NOTES
		struggles: I knew there was a timer cmdlet already from other searches I had done previously;
		measure-command.  Each item it outputs can be manipulated individually so the math will be done
		on those items.  Parameters are used for flexibility; aliaii will be used on parameters for ease
		of typing the command.  I work in an accounting firm so I see a decent amount of work going into
		the reporting side of this one.  Couldn't get totals to pass outside function.  set one as global
		and it went on through.  My global variables were holding their values even after the script was run.
		The values were being carried over inside the Powershell console so I needed to zero them out.  This
		also returns objects so that some fancy formatting can be done on the output as well.  I did have
		some formatting built into the output but decided on just creating objects as the output for everything
		and leaving it up to the end user to decide the output.  Still not sure on error handling; just let PS do it.
		Just figuring out how to present the detailed report was a fun complexity.  Getting the spacing right and
		all the little columns to line up was the challenge.  Also the first time I had created an array like that.
		An earlier script would have benifited from this technique instead of running into issues with constantly
		over-writing the PS-NewObejct that was created.  I probably won't get a star for the clean code because
		of the detailed report, but I like it.

#>

param([Alias("cs")][ScriptBlock]$CommandString={Start-Sleep -seconds 5},[Alias("it")][String]$Iterations="5",[string]$Detail="")

CLS

$Global:TotDays = 0
$Global:TotHours = 0
$Global:TotMin = 0
$Global:TotSec = 0
$Global:TotMil = 0
$Global:Detailed = @()
$Global:Detailed +=,@('Iteration ','Total Days          ','Total Hours         ','Total Minutes       ','Total Seconds  ','Total MilliSeconds')
$Global:Detailed +=,@(('-'*10),('-'*20),('-'*20),('-'*20),('-'*15),('-'*18))

Function CalcRunTimes()
{
	$LoopCounter = 1
	While($LoopCounter -le $Iterations)
	{
		$IndResults = Measure-Command $CommandString
		$Global:TotDays = $Global:TotDays + ($IndResults).TotalDays
		$Global:TotHours = $Global:TotHours + ($IndResults).TotalHours
		$Global:TotMin = $Global:TotMin + ($IndResults).TotalMinutes
		$Global:TotSec = $Global:TotSec + ($IndResults).TotalSeconds
		$Global:TotMil = $Global:TotMil + ($IndResults).TotalMilliSeconds
#generate detailed table of eater iteration run for individual report switch.
#Convert numbers to string to determine number of characters for table formatting
#milliseconds not converted because it did not need any extra spacing
		$TableIterSpacing = $LoopCounter.ToString()
		$TableDaysSpacing = ($IndResults).TotalDays.ToString()
		$TableHoursSpacing = ($IndResults).TotalHours.ToString()
		$TableMinutesSpacing = ($IndResults).TotalMinutes.ToString()
		$TableSecondsSpacing = ($IndResults).Totalseconds.ToString()
		$TableLoopcounter = $Loopcounter,(' '*(10-$TableIterSpacing.Length))
		$TableDays = ($IndResults).TotalDays,(' '*(20-$TableDaysSpacing.Length))
		$TableHours = ($IndResults).TotalHours,(' '*(20-$TableHoursSpacing.Length))
		$TableMinutes = ($IndResults).TotalMinutes,(' '*(20-$TableMinutesSpacing.Length))
		$TableSeconds = ($Indresults).TotalSeconds,(' '*(15-$TableSecondsSpacing.Length))
		$Global:Detailed +=,@($TableLoopCounter, $TableDays, $TableHours, $TableMinutes, $TableSeconds, ($IndResults).TotalMilliSeconds)
		$LoopCounter++
	}
}

CalcRunTimes

$Report = New-Object PSObject
$report | add-member noteproperty -name "command" -value $CommandString
$Report | add-member noteproperty -name "Iterations" -value $Iterations
$Report | add-member noteproperty -name "Days" -value ($Global:TotDays/$Iterations)
$Report | add-member noteproperty -name "Hours" -value ($Global:TotHours/$Iterations)
$Report | add-member noteproperty -name "Minutes" -value ($Global:TotMin/$Iterations)
$Report | add-member noteproperty -name "Seconds" -value ($Global:TotSec/$Iterations)
$Report | add-member noteproperty -name "Milliseconds" -value ($Global:TotMil/$Iterations)

$Report

If($Detail -eq "yes")
{
	ForEach($IndIteration in $Detailed)
		{
		Write-Host($IndIteration)
		}
}
Else
{}
Top

Comments:

4/21/2011 9:54 PM
Chris -
This is one fine script! What are you trying to do get 5 points or something? Because if that is your intention, you succeeded :-)
Now, for some helpful advice: when creating an object in PowerShell 2.0 there is an easier way to do it. Use the -property property and add the items as a hash table. I talk about it a bit on the Scripting Guy blog. I LOVE your very detailed comment based help. You should use verb-noun when naming functions. In your case, Get-RunTimes would be just fine. Use Get-Verb to see approved verbs. You might consider adding Write-progress to your script. waiting for 25 seconds without no notification could cause some people to get antsie ... I know what your script was doing, so that is cool ... I had a series of Scripting Wife articles about write-progress. It is way cool and would be perfect for your script. Again, congrats on a fine script.
4/22/2011 1:31 PM
In an earlier script a judge taled about using the -property but i didn't have an example until the beginner 5 judges answer. Now I know how to do that; looks cleaner too. I had a few more things I wanted to do with this but I ran out of time/brain capacity, like having a check if iterations was over 10 it was going to give a warning it might take some time and would you like a test run.