tim laqua dot com Thoughts and Code from Tim Laqua


VersionOne Nag: Reminding Us To Burn Our Points

You'll forget - we all do. After a hard day of work, the last thing that pops in to your head is "hey, I should go update this story in VersionOne before I go home." Oh no, the only thing you're thinking about is how bad traffic will be, what you're having for dinner, your trip to Seattle, which bar has the best drink specials tonight, etc. So accepting that we forget to burn points now and then, why don't we just make a script to remind us? While you're at it, might as well add a reminder for when you accidentally close a story without setting the ToDo points to zero.

Luckily, since you obviously use VersionOne (because it's the gold standard), there's an API for that:

Note: The following script will request your VersionOne username and password via Read-Host - if you want this to run every day at 4pm, you need to embed your username and password somewhere (securestring support in powershell is helpful, but still - nothing's perfect in this scenario unless you can use LDAP auth)

PowerShell script: v1Nag.ps1

$emailFrom = "whoever.replies@shouldgoto.com"
$emailSMTPServer = "your.smtpserver.com"
$teamName = "Your Team Name in VersionOne"

$url = "https://wwwXXX.v1host.com/yourhostingid/"
$username = Read-Host "User"
$password = Read-Host -assecurestring "Password"

$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))

$apiClient = resolve-path "versionone.sdk.apiclient.dll"
$objectModel = resolve-path "versionone.sdk.objectmodel.dll"
[Reflection.Assembly]::LoadFrom($apiClient) > $NULL
[Reflection.Assembly]::LoadFrom($objectModel) > $NULL
$v1 = new-object VersionOne.SDK.ObjectModel.V1Instance( $url, $username, $password)

$sf = new-object VersionOne.SDK.ObjectModel.Filters.StoryFilter
$v1.Get.Iterations($null) | ? { $_.IsActive } | % { $sf.Iteration.Add($_) }
$v1.Get.Teams($null) | ? { $_.Name -match $teamName } | % { $sf.Team.Add($_) } 
$stories = $v1.Get.Stories($sf)

$memberDetail = @{}

foreach ($story in $stories) {
	foreach ($owner in $story.Owners) {
		if (!$memberDetail.Contains($owner.ID)) { 		
			$md = New-Object PSObject | select Email, DetailEstimate, ToDo, Effort, EffortToday, DoneWithToDo
			$md.Email = $owner.Email;
			$md.DetailEstimate = 0;
			$md.ToDo = 0;
			$md.Effort = 0;
			$md.EffortToday = 0;
			$md.DoneWithToDo = @()
			$memberDetail.Add($owner.ID, $md)
		$memberDetail[$owner.ID].ToDo += $story.ToDo;
		$memberDetail[$owner.ID].DetailEstimate += $story.DetailEstimate;
		if ($story.ToDo -ne 0 -and $story.Status.CurrentValue -eq "Done") {
			$memberDetail[$owner.ID].DoneWithToDo += $story;
		foreach ($effortRecord in $story.GetEffortRecords($null)) {
			$memberDetail[$owner.ID].Effort += $effortRecord.Value;
			if ($effortRecord.CreateDate -ge [DateTime]::Today) {
				$memberDetail[$owner.ID].EffortToday += $effortRecord.Value;

$smtp = new-object Net.Mail.SmtpClient($emailSMTPServer)

$memberDetail.Values | ?{ $_.EffortToday -eq 0 -and $_.ToDo -gt 0} | % { $smtp.Send($emailFrom, $_.Email, "V1 Nag: No Points Burned Down Today", "Please make sure you have recorded any effort completed on your stories for the day.") }

$memberDetail.Values | ?{ $_.DoneWithToDo.Count -gt 0 } | % { $smtp.Send($emailFrom, $_.Email, "V1 Nag: Story Marked As Done With ToDo Balance", "Please make sure you have zero'd out ToDo on your Completed/Done stories.") }

You'll need to download the .NET SDK and build the requisite DLLs from:

Comments (0) Trackbacks (0)

No comments yet.

Leave a comment

No trackbacks yet.