{"id":1313,"date":"2016-04-13T10:00:00","date_gmt":"2016-04-13T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/premier_developer\/?p=1313"},"modified":"2019-03-26T09:58:49","modified_gmt":"2019-03-26T16:58:49","slug":"tips-for-writing-powershell-scripts-to-use-in-build-and-release-tasks","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/tips-for-writing-powershell-scripts-to-use-in-build-and-release-tasks\/","title":{"rendered":"Tips for Writing PowerShell Scripts to Use in Build and Release Tasks"},"content":{"rendered":"<p>Premier Developer ALM Consultant Dave Burnison brings us this awesome collection of tips and tricks for using PowerShell in VSTS and TFS.<\/p>\n<hr \/>\n<p>You can now do almost anything in your build and release definitions in VSTS and TFS 2015. One of the most powerful ways to add your specific logic is to use the <a href=\"https:\/\/msdn.microsoft.com\/library\/vs\/alm\/build\/scripts\/index\">PowerShell task<\/a> or the <a href=\"https:\/\/github.com\/Microsoft\/vso-agent-tasks\/tree\/master\/Tasks\/PowerShellOnTargetMachines\">PowerShell on Target Machines task<\/a>. The documentation that I have found shows you how to use these tasks but, it does not provide many details on how to manage your scripts or write PowerShell scripts that provide feedback to the user via the build and release hubs in Team Web Access. The goal of this blog is to show you how to use some of the commands that are documented <a href=\"https:\/\/github.com\/Microsoft\/vso-agent-tasks\/blob\/master\/docs\/authoring\/commands.md\">here<\/a> in your TFS Build and\/or Release definitions when calling a PowerShell script. I will also show you how to manage shared scripts that can be used across team projects. The examples are from my VSTS account but, as of the time I am writing this, these examples are valid for on-premises TFS as well (TFS 2015 Update 2). For these examples, my source code is stored in TFVC.<\/p>\n<h3>Sharing Scripts Across Team Projects<\/h3>\n<p>I have a <b>HelloWorld<\/b> team project that has the application that I am going to build (e.g. $\/HelloWorld\/Main\/HelloWorld.sln) and a <b>Build<\/b> team project that has common scripts that I want to use in multiple team projects (e.g. $\/Build\/PSScripts). I can see both source trees in Visual Studio.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-35924\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script1.png\" alt=\"\" width=\"429\" height=\"319\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script1.png 429w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script1-300x223.png 300w\" sizes=\"(max-width: 429px) 100vw, 429px\" \/><\/p>\n<p>When you first define a PowerShell script task it appears that you can only select scripts that live in the current team project. I cannot navigate to $\/Build\/PSScripts while in the <b>HelloWorld <\/b>team project.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image552.png\"><img decoding=\"async\" style=\"padding-top: 0px; padding-left: 0px; padding-right: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image_thumb429.png\" alt=\"image\" width=\"804\" height=\"621\" border=\"0\" \/><\/a><\/p>\n<p>To get around this, let\u2019s first, add a mapping to $\/Build\/PSScripts on the <b>Repository <\/b>tab of the <b>HelloWorld \u2013 Main<\/b> build definition to create a <b>Build<\/b> folder in the local workspace on the build agent.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image553.png\"><img decoding=\"async\" style=\"padding-top: 0px; padding-left: 0px; padding-right: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image_thumb430.png\" alt=\"image\" width=\"605\" height=\"432\" border=\"0\" \/><\/a><\/p>\n<p>Now I\u2019ll edit my PowerShell tasks. I cannot navigate to $\/Build\/PSScripts\u2026however, I can manually enter the scripts folder that is now part of the build workspace in the <b>Script filename<\/b> box. Please note how I am using the <b>$(build.sourcesDirectory)<\/b> variable in the path to the .PS1 file.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/clip_image0052.png\"><img decoding=\"async\" style=\"padding-top: 0px; padding-left: 0px; padding-right: 0px; border-width: 0px;\" title=\"clip_image005\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/clip_image005_thumb1.png\" alt=\"clip_image005\" width=\"799\" height=\"614\" border=\"0\" \/><\/a><\/p>\n<h3>Set a variable in one PowerShell task and access the updated value in subsequent tasks<\/h3>\n<p>Using variables in PowerShell scripts is documented <a href=\"https:\/\/msdn.microsoft.com\/en-us\/Library\/vs\/alm\/Build\/scripts\/variables\">here<\/a>. If you just set the variable like this <span style=\"font-family: Consolas;\"><span style=\"color: #ff0000;\">$env:DynamicVariable<\/span> = <span style=\"color: #800000;\">&#8220;Temporary Value Set In Script&#8221;<\/span><\/span>, the scope of the new value is only within the current task, (see \u201c1\u201d in the image below). To set a variable in one PowerShell task and access the updated value in subsequent tasks you need to use a special command: <span style=\"font-family: Consolas;\"><span style=\"color: #0000ff;\">Write-Host<\/span> <span style=\"color: #800000;\">&#8220;##vso[task.setvariable variable=DynamicVariable]Persistent Value Set In Script&#8221;<\/span><\/span>, (see \u201c2\u201d in the image below).<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-35926\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script2.png\" alt=\"\" width=\"794\" height=\"524\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script2.png 794w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script2-300x198.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script2-768x507.png 768w\" sizes=\"(max-width: 794px) 100vw, 794px\" \/><\/p>\n<h3>Set progress and current operation for current task<\/h3>\n<p>My PowerShell script has a long running process so I want to provide a progress indicator in my build output. First I use <span style=\"font-family: Consolas;\"><span style=\"color: #0000ff;\">Write-Host<\/span> <span style=\"color: #800000;\">&#8220;Begin a lengthy process&#8230;&#8221;<\/span><\/span> to indicate that I am starting a long running process. Second I use the <span style=\"font-family: Consolas;\"><span style=\"color: #0000ff;\">Write-Host<\/span> <span style=\"color: #800000;\">&#8220;##vso[task.setprogress value=<span style=\"color: #ff0000;\">$i<\/span>;]Sample Progress Indicator&#8221;<\/span><\/span> command to update the progress. The progress indicator is displayed next to the name of the PowerShell script task, (see the PowerShell code inset in the image below).<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-35927\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script3.png\" alt=\"\" width=\"790\" height=\"594\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script3.png 790w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script3-300x226.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script3-768x577.png 768w\" sizes=\"(max-width: 790px) 100vw, 790px\" \/><\/p>\n<h3>Displaying Warnings and Errors in the build output<\/h3>\n<p>You can leverage the <span style=\"font-family: Consolas;\"><span style=\"color: #0000ff;\">Write-Warning<\/span> <\/span>&amp; <span style=\"font-family: Consolas;\"><span style=\"color: #0000ff;\">Write-Error<\/span> <\/span>PowerShell commands to display warnings and errors, or you can use the TFS specific <span style=\"color: #800000; font-family: Consolas;\">task.logissue<\/span> command to ensure the warnings and errors appears in the build summary. Here are the various commands:<\/p>\n<p><span style=\"font-family: Consolas;\">1. <span style=\"color: #008000;\"># The following will appear in the console output preceded by &#8220;WARNING: &#8221;\n<\/span><span style=\"color: #0000ff;\">Write-Warning<\/span> <span style=\"color: #800000;\">&#8220;This is a warning generated in a PowerShell script&#8221;<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas;\">2. <span style=\"color: #008000;\"># The following will appear Build Summary as a Warning and in the task specific log in YELLOW text.\n<\/span><span style=\"color: #0000ff;\">Write-Host<\/span> <span style=\"color: #800000;\">&#8220;##vso[task.logissue type=warning;] PowerShell Warning Test&#8221;<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas;\">3. <span style=\"color: #008000;\"># The following will appear in the Build Summary and the console output with additional error information&#8221;.\n<\/span><span style=\"color: #0000ff;\">Write-Error<\/span> <span style=\"color: #800000;\">&#8220;This is an error generated in a PowerShell script&#8221;<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas;\">4. <span style=\"color: #008000;\"># The following will appear Build Summary as an Error and in the task specific log in YELLOW text.\n<\/span><span style=\"color: #0000ff;\">Write-Host<\/span> <span style=\"color: #800000;\">&#8220;##vso[task.logissue type=error;] PowerShell Error Test&#8221;<\/span><\/span><\/p>\n<p>Here is what the output looks like in the console window as the build is running.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-35928\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script4.png\" alt=\"\" width=\"778\" height=\"513\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script4.png 778w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script4-300x198.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script4-768x506.png 768w\" sizes=\"(max-width: 778px) 100vw, 778px\" \/><\/p>\n<p>Here is what the output looks like in the Build Summary after the build has completed.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-35929\" src=\"http:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script5.png\" alt=\"\" width=\"780\" height=\"551\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script5.png 780w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script5-300x212.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2016\/04\/script5-768x543.png 768w\" sizes=\"(max-width: 780px) 100vw, 780px\" \/><\/p>\n<h3>Bonus Info: Add your own section to the <b>Build Summary<\/b> output<\/h3>\n<p>If you want to add your own section to the Build Summary refer to the <a href=\"https:\/\/github.com\/Microsoft\/vsts-extension-samples\">VSTS Extension Samples on GitHub<\/a>, Look specifically at the &#8220;<b>Build Results Enhancer<\/b>&#8221; section.<\/p>\n<h3>Sample PowerShell Scripts<\/h3>\n<p>See the attached file, <a href=\"https:\/\/github.com\/PremierDeveloper\/BuildReleaseTasks2015\" rel=\"attachment wp-att-1331\">VSTSPowerShellScripts<\/a>, for the two scripts I used in my examples above.<\/p>\n<p>I\u2019ve given you a taste of how to make your PowerShell scripts work in harmony with the VSTS\/TFS Build and Release systems. For more details on the commands that I have used and additional commands that are available, refer to <a href=\"https:\/\/github.com\/Microsoft\/vso-agent-tasks\/blob\/master\/docs\/authoring\/commands.md\">this documentation on GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Premier Developer ALM Consultant Dave Burnison brings us this awesome collection of tips and tricks for using PowerShell in VSTS and TFS. You can now do almost anything in your build and release definitions in VSTS and TFS 2015. One of the most powerful ways to add your specific logic is to use the PowerShell [&hellip;]<\/p>\n","protected":false},"author":582,"featured_media":37840,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[34,194,102,121,46,379,38],"class_list":["post-1313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-permierdev","tag-alm","tag-dave-burnison","tag-powershell","tag-tfs","tag-visual-studio","tag-visual-studio-team-system","tag-vsts"],"acf":[],"blog_post_summary":"<p>Premier Developer ALM Consultant Dave Burnison brings us this awesome collection of tips and tricks for using PowerShell in VSTS and TFS. You can now do almost anything in your build and release definitions in VSTS and TFS 2015. One of the most powerful ways to add your specific logic is to use the PowerShell [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=1313"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1313\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=1313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=1313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=1313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}