Part 14: Execute a PowerShell script
In the series the following parts have been published     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      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:     Open the command prompt     To run the script you must change the execution policy. To do this execute in the command prompt:            powershell set-executionpolicy remotesigned           Now go to the directory where you have saved the PowerShell script     Execute the following command            powershell .\HelloWorld.ps1            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     Add a new argument called “DeploymentScript” and set the appropriate settings in the metadata. See Part 2: Add arguments and variables  for more information.     Scroll down beneath the TryCatch activity called “Try Compile, Test, and Associate Changesets and Work Items”     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.     Add in the Then branch of the If activity a new Sequence activity and rename it to “Start deployment”     Click on the activity and add a new variable called DeploymentScriptFilename (scoped to the “Start deployment” Sequence     Add a ConvertWorkspaceItem activity on the “Start deployment” Sequence     Add a InvokeProcess activity beneath the ConvertWorkspaceItem activity in the “Start deployment” Sequence     Click on the ConvertWorkspaceItem activity and change the properties      DisplayName = Convert deployment script filename       Input = DeploymentScript       Result = DeploymentScriptFilename       Workspace = Workspace     Click on the InvokeProcess activity and change the properties      Arguments = String.Format(" ""& '{0}' "" ", DeploymentScriptFilename)       DisplayName = Execute deployment script       FileName = "PowerShell"     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.     Do the same for a WriteBuildError activity on the "Handle Error Output"     To publish it, check in the Build Process Template    This leads to the following result    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.    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    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.     Add a new Argument called DeploymentScriptParameter     In the InvokeProcess activity where the PowerShell command is executed, modify the Arguments property to String.Format(" ""& '{0}' '{1}' "" ", DeploymentScriptFilename, DeploymentScriptParameter)     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.      You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.