Sharing files between Host/VM

Since Windows 8.1 I have had Hyper-V installed on my machine. As an MVP I do a lot of demo’s so this is wonderful. I used to have a spare machine running Windows 2008 just for this.

One thing I have found difficult to do, is share files between my VM and the host machine. All the solutions I was coming across were just not as simple as I would like. Until now. I came across this Blog which outlines 5 ways to achieve this.

Below is, in my opinion the easiest way to share files between a host and VM.

1. Start Hyper-V Manager
2. Right click the Hyper-V host and select "Hyper-V Settings"










3. Ensure the tick box is ticked under Enhanced Session Mode and click OK.








4. Right click the virtual machine-> Settings -> Integration Services at bottom left hand side of the menu.
5. Check "Guest Services" and click OK.












6. Start up the virtual machine, copy files from physical machine and paste in to virtual the machine!

Build and Release Tasks with DropDown Arguments

I have been creating a lot of Build Tasks for the new TFS 2015 Build and Release.

I have discovered a few tricks that were not simple to find. I thought I would Blog about them for my own record and anyone who happens by.

This Blog post makes the assumption that you have already been creating your own build tasks. If not, and you want some background take a look here first.

In this example I created a Release task to perform a DACPAC deployment. The script calls SQLPackage.exe which can do several things. Deploy the changes directly to a Database or generate a Deployment Report, a Drift Report or the SQL that needs to be run to update the target, amongst others.

So I figured I would make my Build Task smart enough to let the end user select which action they would they would like to perform. To do that I need the user to select which action and have that passed into my Powershell script.

The input value that is defined in my task.json file looks like this.

   "name": "action",
   "type": "pickList",
   "label": "Action",
   "defaultValue": "Publish",
   "required": true,
   "helpMarkDown": "Select the Action to perform",
   "options": {
     "Publish": "Publish Changes",
     "Script": "Script Changes",
     "DeployReport": "Generate Deployment Report"

The type needs to be “picklist”. I also needed to define options. Each option is comprised of two strings seperated by a semicolon. The string before each semicolon is the value to be returned and the string after the semicolon is the display name. Notice I set one of the values to be the defaultValue.

Once published to TFS the build task inputs will look something like this.









Now the selected value will be passed into my Script and I can change my call to SQLPackage.exe accordingly.

Making a TFS Build wait

In my career I have created Automated builds for many different technologies. TFS never lets me down. The old XAML build did a good job however the new TFS 2015 Builds are awesome. First of all I love PowerShell, which makes my life much easier. I can just call out to a script sitting in source control or better yet create my own Build Task and upload it to the server.

I recently had to create a build for a development tool that generates documents from various system data. This tool has it’s own editor, version control,  release management everything. It’s kind of a closed eco system.

So how do we get the rest of the team involved in it’s builds and deployments. How do I trigger a build and have this system drop a deployable package for me, that I can deploy to different environments without having to ask the developers? Letting QA be responsible for their own environment.

After talking with an expert in this tool. It turns out, it also has an automation component. The developers can write scripts to perform builds and deployments. However we want this to be part of a larger eco system with our other applications.

It was decided that we would create a file share on the network where I could drop a file to let the other system know I wanted a new build dropped. This way TFS would still generate a build number the testers can deploy to the QA environment and reference from their test plan so we get the full end to end traceability.

So I wrote a script that would drop a file (Build.txt) in a known location on the network. Said products automation tool watches for my file and triggers a script to perform a build when it sees it and then drops that build package back for me to turn into a build artifact. I will put the build number in this file so the other system can use that as a label in it’s own Version Control system.

Then the build waits and watches for a file named BuildComplete.txt to be placed back in that working folder. When my build sees it I know the built package is there and I can create a build artifact. By the way the BuildComplete.txt either contains the word successful or an error log if something went wrong. I will pull that out and toss it up into the build console.

My build has two tasks one to Drop the file that triggers the other system and one to create a build artifact. The second one is already built into TFS “Copy and Publish Build Artifacts”. The first step is one Powershell script. See below with Comments:

The Powershell script takes two arguments The WorkingFolder and a timeout.





The comments in line explain how it works.

   1: param()
   3: #This is how we do parameters in a custom build task 
   4: Trace-VstsEnteringInvocation $MyInvocation
   5: try {
   6:     Import-VstsLocStrings "$PSScriptRoot\Task.json" 
   7:     [int32]$timeout = Get-VstsInput -Name TimeOut
   8:     [string]$WorkingFolder = Get-VstsInput -Name WorkingFolder 
   9: } 
  10: finally 
  11: { 
  12:      Trace-VstsLeavingInvocation $MyInvocation 
  13: } 
  15: #Start the Timer at zero
  16: $timesofar = 0
  17: #This is the file we are looking for to know the package is complete 
  18: $BuildComplete = "$WorkingFolder\BuildComplete.txt"
  19: #Clean the Working Folder
  20: Remove-Item  "$WorkingFolder\*"
  21: #Create file containing Build number to trigger the build
  22: New-Item -path "$WorkingFolder" -name 'Build.txt' -type 'file' -value "$env:BUILD_BUILDNUMBER"
  24: Write-Host "Triggered Build"
  25: #While BuildComplete.txt does not exist and timer has not reached the timeout specified
  26: while (!(Test-Path $BuildComplete) -and !($timesofar -eq $timeout)) 
  27: { 
  28:     #Wait for 10 seconds
  29:     Start-Sleep 10 
  30:     #Add 10 seconds to the time So Far
  31:     $timesofar = $timesofar + 10
  32: }
  34: #Either the File has been dropped by the other system or the timeout was reached
  35: if (!(Test-Path $BuildComplete)) 
  36: {
  37:     #If the file was not dropped it must be the timeout so fail the build write to the console
  38:     Write-Error "Build Timed out after $timeout seconds."
  39: }
  40: else
  41: {
  42:     #If we got here the file was dropped
  43:     #Get the content of the file
  44:     $BuildResult = Get-Content $BuildComplete -Raw
  46:     #Check if it says successful
  47:     if ($BuildResult.StartsWith("successful"))
  48:     {
  49:         #On Success say so
  50:         Write-Host "Successful Build"
  51:         #write the contents out in case the calling system wants to tell us something
  52:         write-Host "$BuildResult"
  53:     }
  54:     else
  55:     {
  56:         #On Error Faile the build and say so 
  57:         Write-Error "Build Error"
  58:         #write the contents out so we can see why it failed
  59:         Write-Error "$BuildResult"
  60:     }
  61: }

Build Toronto June 10th 2016

  • 400+ attendees in Toronto (Allstream Centre)
  • 1000+ attendees online on Channel 9 with live Q&A
  • Keynote highlighting the most important announcements from Build 2016.
  • Deep Dive sessions on Universal Windows Platform, Xamarin, Web Apps, Project Centennial, and Azure IoT.
  • Live Panel discussion with influential members of the CDN Dev Community
  • Free to attend. Space is limited.

DevOps Days Hackathon Toronto

One day DevOps Hackathon event is coming to Toronto on May 25th. It's a full day event where you will get a chance to chance for some hands-on learning experience with DevOps concepts and automation using tools from Microsoft & Chef. Here is an agenda for hackathon event:


9:00 AM – 9:30 AM Registration, Breakfast & Introduction

9:30 AM – 10:00 AM Session I – DevOps and the Cloud: Microsoft Azure

10:00 AM – 10:45 AM Session II – Chef + Microsoft Azure, Managing your cloud consistently, securely and transparently

11:00 AM – 12:00 PM Hackathon Begins

12:00 PM – 1:00 PM Working Lunch

1:00 PM – 3:00 PM Hackathon Continues

3:00 PM – 4:45 PM Hackathon Ends & Group Presentations (5 min/group)

4:45 PM – 5:00 PM Closing Remarks & Winners Announced


If you are interested in participating, fill free to register at This event will take place a day before DevOps Days Toronto kicks off. It's an excellent event, which is unfortunately already all booked, but hackathon event has only recently opened up and promises to be very informative. So, go ahead and register. It will be fun… See you there.


Tech Days Online

Next week it all happens again! For the fifth year Microsoft United Kingdom is running its TechDays Online event—at no cost to attend. Covering the top topics in IT today, you can watch all the live stream action May 18th and 19th from 9:30am – 5:30pm. Register to attend or catch-up on all the great content here.

As in past years, this popular event has attracted noteworthy speakers from across Microsoft's technical community, including many, many MVPS. The focus this year will be Intelligence and DevOps.

On Wednesday, May 18th, the presentations will feature Analytics on Azure and Cortana Intelligence and explore Microsoft's Intelligent Cloud and the interconnected services called the Cortana Analytics Suite. Technical experts already building these services will explain what these services are, how they fit together to enable organizations to leverage their data and share their own experiences.

On Thursday, May 19th, the theme shifts to DevOps with the MVPs and community leaders talking about the latest practices to enable organizations to increase efficiency. Throughout the day the main technologies discussed will enable viewers to implement DevOps practices within their own organization. As with day one, technical experts and MVPs already taking advantage of these practices will share their journey and real-world experiences with DevOps.

 Here's the agenda (subject to change):

Day One;

Day Two;

Cleanup the GlobalList.Xml

TFS has been using the GlobalList.xml file to store builds since 2010. This Global List is used in several workitems as the suggested list of values. For example, in the Bug there are two fields that use this Found In and Integrated In. These drop down fields present a list of builds that comes from the GlobalList.

Although it's not the great solution and I hear it's changing. It's what we have had for 6 years so we have used it. I have many clients that rely on these work item fields and therefore the list of builds.

However, when you delete a build it cleans up a lot of stuff, including the label, Drop Folder, Symbols and Test Results. But not the entry in the GlobalList. L

Ours was getting out of hand. So I built a Powershell script that I could run that would clean up the Global List by checking to see if the build had been deleted from TFS. If it was removed it removes the build from the list. Because this list is implemented as a Suggested list in the work items removing them has no effect on the old workitems referring to this build. They will still have their value. It just means the cleaned up build will not be in the list to be selected anymore.








#Add the Entry to the Global List


[string] $GlobalListFileName = "GlobalList.xml"

[string] $NewGlobalListFileName = "NewGlobalList.xml"

[string] $RemovedBuilds = "RemovedBuilds.xml"

[String] $GlobalListName = "Builds - MyProject"

[string] $tfsServer = "http://TFSServer:8080/tfs/Collection"

[string] $witadmin = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\witadmin.exe"



#Export GlobalList

$arguments = 'exportGloballist /collection:"' + $tfsServer + '" /f:"' + $GlobalListFileName + '"'

write-host $witadmin $arguments

start-process -FilePath $witadmin -Argumentlist $arguments -wait -WindowStyle Hidden


#Connect to TFS and get the Build Server

$server = new-object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection(New-Object Uri($tfsServer))

$buildServer = $server.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])


#Load the contents of GlobalList.xml

[xml]$doc = Get-Content($GlobalListFileName)

$root = $doc.DocumentElement

$node = $root.SelectSingleNode("GLOBALLIST[@name='Builds - MyProject']")


#Create a list of builds that are no longer in TFS

foreach ($child in $node.ChildNodes)


[array]$items = $child.value.Split("/")

$buildDetail = $buildServer.QueryBuilds("MyProject", $items[0]) | ? { $_.BuildNumber -eq $items[1] }

if ($buildDetail)


write-host "$($items[1]) is Valid" -ForegroundColor yellow




add-content -path $RemovedBuilds -value " <LISTITEM value=""$($child.value)"" />"

write-host "$($items[1]) was Removed" -ForegroundColor Red




#Compare the list of removed builds with the original list spit out the difference into a New GlobalList

(compare-object (get-content $GlobalListFileName) (Get-Content($RemovedBuilds))).inputObject | set-content $NewGlobalListFileName



#Import the new GlobalList

$arguments = 'importgloballist /collection:"' + $tfsServer + '" /f:"' + $NewGlobalListFileName + '"'

write-host $witadmin $arguments

start-process -FilePat $witadmin -Argumentlist $arguments -wait -WindowStyle Hidden

TFS chart size limits

TFS is an excellent ALM/DevOps tool. Very flexible ALM/DevOps tool. You can do a lot with it. A lot. Once in a while though, like with any other tool, you hit a hurdle that prevents you from doing what you and/or the customer is trying to do with TFS. For example, recently I encountered the following error: VS402395: The daily number of work items returned exceeds the trend chart size limit of 1000. An error was caused because the customer was trying to build a chart from a query that returns more than 1,000 work items. I questioned why would they need a chart for a query that big, and the customer seemed to have a good reason to have chart for that many items. I might not agree with that reason, but the customer thought it was important, so I've promised to look into it.

And, of course, if there is a will, there is a way. Especially, if you're dealing with a flexible and feature rich TFS. TFS has a very rich API. And, almost always, if there is something that you cannot do in UI, you can do via API. Just like in this case. Even though, there was no way to by part chart size limit, there is a very straightforward to get it done using API. OK, enough talk. Here is how you can change chart size limit using PowerShell and TFS API:


# Load TFS snapin

if ( (Get-PSSnapin -Name Microsoft.TeamFoundation.PowerShell -ErrorAction SilentlyContinue) -eq $null )


Add-PSSnapin Microsoft.TeamFoundation.PowerShell






$tfsCollection = New-Object -TypeName Microsoft.TeamFoundation.Client.TfsTeamProjectCollection TFS_COLLECTION_URL

$hiveCollection = $tfsCollection.GetService([Microsoft.TeamFoundation.Framework.Client.ITeamFoundationRegistry])


Write-Output "The current value of chart size limit is:"


Write-Output "Changing the chart size limit to 1500 (maximum)…"

$hiveCollection.SetValue("/Service/WorkItemTracking/Settings/MaxTrendChartTimeSliceResultSize", 1500)

Write-Output "The new setting for a chart size limit is:"




That's it. Have a good day J

Trigger a Release add the Build to GlobalList

This was never the best solution but it worked. When a build executed it would be added to the Collections Global List. Then it could be used as the source for drop downs like Found In Build and Integrated In Build.

If you are stuck in that place between TFS 2015 U1 and U2 you have the news builds but you don't have the new Release manager yet these two PowerShell Scripts might come in Handy.

There are so many environment variables you can use to get information about the build that you are a part of, the CollectionURI, SourcesDirectory and so on. You can check them all out here.

To save space I have left out error checking.

  1. Trigger a release in ReleaseManager from the 2015 vNext build

# Environment Variables


Write-Host "Project: $env:SYSTEM_TEAMPROJECT"

Write-Host "Build Def: $env:BUILD_DEFINITIONNAME"

Write-Host "Build Number: $env:BUILD_BUILDNUMBER"



$TFSUri = $TFSUri.Replace("/tfs/",":8080/tfs/")

write-host "URI - $TFSUri"


$binaryLocation = join-path (Get-ItemProperty $registrykey[0]).InstallDir "bin\ReleaseManagementBuild.exe"


# Call Release Management Build

&"$binaryLocation" release -tfs "$TFSUri" -tp "$($env:SYSTEM_TEAMPROJECT)" -bd "$($env:BUILD_DEFINITIONNAME)" -bn "$($env:BUILD_BUILDNUMBER)"



  1. Add the Build to the GlobalList

#Use Environment Variables to get Build Information

[String] $GlobalEntryValue = "$env:BUILD_DEFINITIONNAME/$env:BUILD_BUILDNUMBER"


#Some other information that you will need

[string] $GlobalListFileName = "GlobalList.xml"

[String] $GlobalListName = "Builds - MyProject"


[string] $witadmin = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\witadmin.exe"


#Export GlobalList

$arguments = 'exportGloballist /collection:"' + $tfsServer + '" /f:"' + $GlobalListFileName + '"'

write-host $witadmin $arguments

start-process -FilePath $witadmin -Argumentlist $arguments -wait -WindowStyle Hidden



#Add the Entry to the Global List

Write-host "Add build $env:BUILD_BUILDNUMBER to $GlobalListName"

[xml]$doc = Get-Content($GlobalListFileName)

$List = $doc.GLOBALLISTS.GLOBALLIST | ? { $_.Name -eq $GlobalListName }

$build = $doc.CreateElement("LISTITEM")






#Import GlobalList

$arguments = 'importgloballist /collection:"' + $tfsServer + '" /f:"' + $GlobalListFileName + '"'

write-host $witadmin $arguments

start-process -FilePath $witadmin -Argumentlist $arguments -wait -WindowStyle Hidden


Microsoft Events

TechNet Virtual Summit

3 days of expert content on IT shifts, career insights, security, mobility, tech innovations and more. Hear firsthand where IT is heading, from some of the best tech minds in the business. Join us online March 1-3 right from your favorite connected device. Register here: and share with your community! Note:  sessions will be delivered in PST Time.

Let's Dev This Tour in Montreal

On March 30st, Let's Dev This Tour is coming to Montreal to present 3 different tracks on Web, Cloud and Windows 10. To know more about each session simply click on it.

Microsoft DevOps Hackathon

DevOps Hackathon is happening in Montreal on March 18-19th and in Ottawa on March 31st- April 1stPlease see below call for MVP Proctors.

MVP Open Day 2016 – this year's Canadian MVP Open Day will take place on Friday, May 6th, 2016 (8:30am – 5pm EST). Please make sure you register here

ITI Cloud Roadshows: Join local IT professionals and Microsoft MVPs in the following cities:

MVP Days Community Roadshow: coming to Toronto Feb 29th, Ottawa Mar 2nd, and Montreal Mar 4th, 2016. We are hoping you are able to register for these events. Please help us spread the word.

SharePoint Saturday Montreal: Register for the 4th Edition of SharePoint Saturday in Montreal on April 2, 2016. Five tracks offered: IT Pro, Dev, End-User, Business Customer Showcase and Data SQL. Call for Speakers and Sponsors are open!

Prairie Dev Conference: 2-days Development Conference happening in Winnipeg on April 11-12th, 2016 -