Part 14: Execute a PowerShell script

by Ewald Hofman 9. November 2010 05:32

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

With PowerShell you can add powerful scripting to your build to for example execute a deployment. If you want more information on PowerShell, please refer to http://technet.microsoft.com/en-us/library/aa973757.aspx

For this example we will create a simple PowerShell script that prints “Hello world!”. To create the script, create a new text file and name it “HelloWorld.ps1”. Add to the contents of the script:

Write-Host “Hello World!”

To test the script do the following:

  1. Open the command prompt
  2. To run the script you must change the execution policy. To do this execute in the command prompt:

    powershell set-executionpolicy remotesigned
  3. Now go to the directory where you have saved the PowerShell script
  4. Execute the following command

    powershell .\HelloWorld.ps1

image_thumb1

In this example I use a relative path, but when the path to the PowerShell script contains spaces, you need to change the syntax to

powershell "& '<full path to script>' "

for example:

powershell "& ‘C:\sources\Build Customization\SolutionToBuild\PowerShell Scripts\HellloWorld.ps1’ "

In this blog post, I create a new solution and that solution includes also this PowerShell script. I want to create an argument on the Build Process Template that holds the path to the PowerShell script. In the Build Process Template I will add an InvokeProcess activity to execute the PowerShell command. This InvokeProcess activity needs the location of the script as an argument for the PowerShell command. Since you don’t know the full path at the build server of this script, you can either specify in the argument the relative path of the script, but it is hard to find out what the relative path is. I prefer to specify the location of the script in source control and then convert that server path to a local path. To do this conversion you can use the ConvertWorkspaceItem activity.

So to complete the task, open the Build Process Template CustomTemplate.xaml that we created in earlier parts, follow the following steps

  1. Add a new argument called “DeploymentScript” and set the appropriate settings in the metadata. See Part 2: Add arguments and variables  for more information.
  2. Scroll down beneath the TryCatch activity called “Try Compile, Test, and Associate Changesets and Work Items”
  3. Add a new If activity and set the condition to "Not String.IsNullOrEmpty(DeploymentScript)" to ensure it will only run when the argument is passed.
  4. Add in the Then branch of the If activity a new Sequence activity and rename it to “Start deployment”
  5. Click on the activity and add a new variable called DeploymentScriptFilename (scoped to the “Start deployment” Sequence
  6. Add a ConvertWorkspaceItem activity on the “Start deployment” Sequence
  7. Add a InvokeProcess activity beneath the ConvertWorkspaceItem activity in the “Start deployment” Sequence
  8. Click on the ConvertWorkspaceItem activity and change the properties
    DisplayName = Convert deployment script filename
    Input = DeploymentScript
    Result = DeploymentScriptFilename
    Workspace = Workspace
  9. Click on the InvokeProcess activity and change the properties
    Arguments = String.Format(" ""& '{0}' "" ", DeploymentScriptFilename)
    DisplayName = Execute deployment script
    FileName = "PowerShell"
  10. To see results from the powershell command drop a WriteBuildMessage activity on the "Handle Standard Output" and pass the stdOutput variable to the Message property.
  11. Do the same for a WriteBuildError activity on the "Handle Error Output"
  12. To publish it, check in the Build Process Template

This leads to the following result

image_thumb[14]

We now go to the build definition that depends on the template and set the path of the deployment script to the server path to the HelloWorld.ps1. (If you want to see the result of the PowerShell script, change the Logging verbosity to Detailed or Diagnostic). Save and run the build.

image_thumb[16]

A lot of the deployment scripts you have will have some kind of arguments (like username / password or environment variables) that you want to define in the Build Definition. To make the PowerShell configurable, you can follow the following steps.

Create a new script and give it the name "HelloWho.ps1". In the contents of the file add the following lines:

param (
        $person
    )

$message = [System.String]::Format(“Hello {0}!", $person)
Write-Host $message

When you now run the script on the command prompt, you will see the following

image_thumb[18]

So lets change the Build Process Template to accept one parameter for the deployment script. You can of course make it configurable to add a for-loop that reads through a collection of parameters but that is out of scope of this blog post.

  1. Add a new Argument called DeploymentScriptParameter
  2. In the InvokeProcess activity where the PowerShell command is executed, modify the Arguments property to String.Format(" ""& '{0}' '{1}' "" ", DeploymentScriptFilename, DeploymentScriptParameter)
  3. Check in the Build Process Template

Now modify the build definition and set the Parameter of the deployment to any value and run the build.

image_thumb[21]


You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VS 2010

Comments

11/9/2010 5:33:42 AM #

trackback

Part 14: Execute a PowerShell script

Part 14: Execute a PowerShell script

Ewald Hofman |

11/10/2010 9:14:32 AM #

pingback

Pingback from blogs.like10.com

TechDays 2010 Presentations « Microsoft Team Foundation Server, SharePoint Server, .NET, and SQL Server

blogs.like10.com |

11/19/2010 1:32:40 PM #

Peter

Hello! This is exactly what I need. My only question is, are there any additional steps to get the PowerShell output emitted to the TFS build log? I have (or at least think I have; I've double-checked) followed your steps above to WriteMessage the stdOutput and WriteError the stdError. Is there something I should be doing different?

Peter United States |

11/25/2010 6:02:18 AM #

Ewald Hofman

You need to modify either the importance on the build message. See www.ewaldhofman.nl/.../...on-to-the-build-log.aspx

Ewald Hofman Netherlands |

11/29/2010 8:00:15 AM #

Peter

Thanks for the reply!

Peter United States |

11/19/2010 1:35:11 PM #

Peter

To be clear, I see the following output in the log:

POWERSHELL
powershell.exe -NoLogo -NonInteractive -Command . 'C:\REDACTED.ps1' -BuildDirectory:'C:\REDACTED' -SourcesDirectory:'C:\REDACTED' -BinariesDirectory:'C:\REDACTED'

The script is as follows:

param($BuildDirectory, $SourcesDirectory, $BinariesDirectory)

write-host "BuildDirectory: $BuildDirectory"
write-host "SourcesDirectory: $SourcesDirectory"
write-host "BinariesDirectory: $BinariesDirectory"


I have (to ensure the script is running) changed the file to output to a text file, and can verify that the PowerShell script is indeed running. Anyway, I'm just hoping there's an obvious TFS build workflow setting I missed. Thanks, Peter

Peter United States |

12/16/2010 11:58:38 AM #

Jesse

Your comment about how if the path to the script contains a space must specify the full path in single-quotation-marks is not entirely accurate.
You only have to put the portion that contains the spaces in single-quotation-marks.

Example: If the path is C:\Users\Test\Desktop\Folder for Testing Scripts\ you don't have to put the entire thing in quotes (if the path is still relative to where you're calling it from).

Usage:
.\'Folder for Testing Scripts'\testscript.ps1  = works perfectly fine

Jesse United States |

12/30/2010 8:07:01 PM #

Mike Paterson

Is it possible to get the script to execute on one of the VMs created during a Lab Management build?

Mike Paterson United States |

1/3/2011 12:35:49 AM #

Ewald Hofman

Yes, you need to install the lab and build agent in your vm: blogs.msdn.com/.../...nts-controllers-for-lab.aspx

Ewald Hofman Netherlands |

3/29/2011 6:33:07 PM #

michael@1300record.com.au

My Build Fails with Error 'File not found: PowerShell'..
I'm assuming its the Build Agent that executes this.. so as long as that machine has Powershell setup this should work..
Any ideas?

michael@1300record.com.au Australia |

6/2/2011 1:25:52 AM #

k murray

Hi, i am also having the same issue. i have my build set up so that the build controller and agent is on a separate build machine but the solution is on the TFS server. i have added the powershell script to the solution im building but when i run the build i see the following messages PowerShell  "& 'C:\Dev\smartMARKETER(Web)\TestBuild\Sources\HelloWorld.ps1' " followed by File not found: PowerShell. when i look on the build machine, i can see that this file does in fact exist so i have no idea why this isnt working. can anyone shed any light on this please?
Thanks

k murray United Kingdom |

5/19/2011 12:47:48 PM #

Patrick

Hi - I am trying to add a ConvertWorkspaceItem activity to a new build template (copy of DefaultBuiltTemplate). That activity expects an InArgument<Workspace> for the workspace text box. I have tried to enter Workspace, just as you show above, and I keep getting the little red exclamation point and tooltip that says

Compiler error(s) encountered processing expression "Workspace".
'Workspace' is a type and cannot be used as an expression.

This is a brand new solution, brand new team project, no changes made other than copying the defualt build template. VS 2010 SP1, TFS 2010 SP1. Help please... I got everything else here except the workspace text box.

Many thanks for this blog post series, it's been extremely helpful!

Patrick United States |

5/23/2011 1:05:02 PM #

Patrick

Never mind, figured it out. Was at the wrong scope.

Patrick United States |

5/31/2011 8:22:21 AM #

trackback

Ewald’s posts on TFS Build 2010

Ewald Hofman , an ALM MVP, has written a great series of blog posts on Team Build in Team Foundation Server 2010.  The 2010 release introduces Windows Workflow as the overall orchestrator of the build process.  Ewald walks you through quite a few topics related to this and the other new features.  Check it out! Part 1: Introduction Part 2: Add arguments and variables Part 3: Use more complex arguments Part 4: Create your own activity Part 5: Increase AssemblyVersion Part 6: Use custom type for an argument Part 7: How is the custom assembly found Part 8: Send information to the build log Part 9: Impersonate activities (run under other credentials) Part 10: Include Version Number in the Build Number Part 11: Speed up opening my build process template Part 12: How to debug my custom activities Part 13: Get control over the Build Output Part 14: Execute a PowerShell script Part 15: Fail a build based on the exit code of a console application Part 16: Specify the relative reference path Technorati Tags: tfs 2010 , team build , windows workflow

Buck Hodges |

6/19/2011 9:36:22 PM #

trackback

TFS 2010 & Sharepoint 2010: automated build and deploy (remotely)

I just finished work on a project with a lot of v4 technologies (Silverlight, .Net, Entity Framework

Viewpoint |

8/10/2011 9:13:12 AM #

pingback

Pingback from blog.agilepartner.net

Setting up FitNesse for Team Foundation Server | Agile Partner Blog

blog.agilepartner.net |

Comments are closed

Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen


ClusterMap

Statistics

Statistics created at 09 Sep 2009

121 posts
493 comments
328 raters
1951835 visit (1042 per day)
22 users online

Recent comments

Comment RSS