PowerShelling your Deployment Emails

QA and Development departments team members coordinate at many points along the software development life cycle (SDLC). Part of this communication revolves around deployments, which often take the form of an e-mail that includes information from Team Foundation Server(TFS). To achieve success, multiple points need to be communicated.

  1. When – It needs to be clear when a deployment is finished and the environment is ready for testing
  2. What – The stories/Product Backlog Items (PBI’s)/Bugs that are included in the build
  3. Where – The environments that will be changed and/or updated as a result of the release

The below script will lookup the provided items in TFS, update them and send relevant information in an email. I highly recommend using distribution lists for emails like this. It facilitates people subscribing and unsubscribing without updating the script.


$From = $env:username + "@domain.com"
$TFSServer = "http://tfsServer:8080/tfs/Collection"
$body = ""
$Subject = "IMPORTANT: QA DEPLOYMENT for Your Site Announcement COMPLETE"
$recipients = $From
#Prevent e-mails from going out before you are ready
#$recipients = "Deployment QA Distribution List"
$cc = ""
$bcc = $From
$Pbis = "10899", "10950" #enter PBI's here
$QAAssignee = 'QA Rockstar'
Function Get-WorkItems
{
$query = "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.IterationPath] " +
"FROM WorkItems WHERE [System.Id] In (" + [System.String]::Join(",", $Pbis) + ")"
Write-Host $query
tfpt query /format:tsv /collection:$TFSServer /wiql:$query
foreach ($PBI in $Pbis)
{
Write-Host "Setting Assigned To = $QAAssignee for PBI # $PBI"
$fields = "Assigned To=$QAAssignee"
# This just captures the output so it doesn't get included in the e-mail below
$test = tfpt workitem /collection:$TFSServer /update $PBI /fields:$fields
}
$query = ""
}
Function TsvToHtmlTable()
{
$results = Get-WorkItems
$results = $results -replace "(.*)Query results:.*", "$1"
$count = 0;
$table = "<table>"
$class = "gray"
foreach ($line in $results)
{
if (![string]::IsNullOrWhiteSpace($line))
{
$table += "<tr class='" + $class + "' id='" + $count + "'>"
$class = if($count % 2 -eq 0) { "even" } else { "odd" }
foreach($chunk in $line.Split("`t"))
{
if (![string]::IsNullOrWhiteSpace($chunk))
{
$table += "<td>" + $chunk.Trim() + "</td>"
}
}
$table += "</tr>`r`n"
$count += 1
}
}
return $table + "</td></tr></table>"
}
$body += @"
<style type='text/css'>
table { width:100%; border-collapse:collapse}
table td{ padding:7px; border:black 1px solid}
.gray {background: #808080}
.even {background: #b8d1f3}
tr#0 {font-weight: bold}
</style>
"@
$body += "<b>Hello,</b><br><br>`r`n"
$body += "<b>Summary</b><br><br>We just completed a QA deployment for the product (" + [System.DateTime]::Now.ToString() + ")<br><br>`r`n"
$body += "<b>Environment</b><br>QA<br>The servers involved can be accessed at: "
$body += "<br>http://url1<br&gt;`r`n"
$body += "<br>http://url2<br><br&gt;`r`n"
$body += "<b>Actions</b><br>The following items will have to be tested in the QA environment after deployment.<br><br>`r`n"
$body += TsvToHtmlTable
Send-MailMessage `
-Subject $Subject `
-BodyAsHtml $body `
-From $From `
-To $recipients `
-Bcc $From `
-SmtpServer "smtpServer" `
-port 25

In this example, the person executing the script would need to enter the PBI’s that are going to be deployed. Then the script will query TFS to retrieve the relevant information to include in the e-mail (Id, Title, Type, Iteration, Assigned To). In our case, part of the deployment included assigning the stories/PBI’s/Bugs to a QA user for clarity and historical record. To prevent mismatches between the e-mail and assignment, the script updates the AssignedTo for each provided item.

The output of the query comes in a tab separated vector (tsv) format. The TsvToHtmlTable function converts the output from tsv to something (aka html) that looks decent within an email. The endpoints listed in the e-mail remove guesswork about where to find the environment and perform testing.

For me, investing the time and energy into these communications helped foster trust and collaboration between Dev and QA. I hope it helps you achieve the same, if not more.