{"id":219,"date":"2013-12-07T09:11:41","date_gmt":"2013-12-07T16:11:41","guid":{"rendered":"http:\/\/www.jsnover.com\/blog\/?p=219"},"modified":"2023-12-25T07:10:01","modified_gmt":"2023-12-25T14:10:01","slug":"write-host-considered-harmful","status":"publish","type":"post","link":"https:\/\/www.jsnover.com\/blog\/2013\/12\/07\/write-host-considered-harmful\/","title":{"rendered":"Write-Host Considered Harmful"},"content":{"rendered":"<p><span style=\"color: #0000ff;\">[<strong>2023 Update]<\/strong> \u00a0<\/span><\/p>\n<p><span style=\"color: #0000ff;\">I\u2019ve been meaning to update this for a while. \u00a0The advice in this post is no longer current. \u00a0A while ago we changed the implementation of Write-Host to being a wrapper on top of Write-Information. \u00a0Prior to this, when you used Write-Host, there was no way to capture and process the data you wrote &#8211; because it just wrote to the host. \u00a0Now that it uses Write-Information, it goes through a path that writes to the host AND allows you to capture and process that information.<\/span><br \/>\n<span style=\"color: #0000ff;\">-Jeffrey Snover<\/span><\/p>\n<p><span style=\"color: #0000ff;\">[<strong>End 2023 Update]<\/strong><\/span><\/p>\n<p>When you are writing or reviewing PowerShell scripts, I&#8217;d like you to remember the following rule of thumb:<\/p>\n<ul>\n<li><strong>Using\u00a0<a title=\"Using the Write-Host Cmdlet\" href=\"http:\/\/technet.microsoft.com\/en-us\/library\/ee177031.aspx\" target=\"_blank\" rel=\"noopener\">Write-Host<\/a>\u00a0is almost always wrong.<\/strong><\/li>\n<\/ul>\n<p><!--more-->Write-Host is almost always the wrong thing to do because it interferes with automation. \u00a0 There are typically two reasons why people use Write-Host:<\/p>\n<p><strong>To convey results.<\/strong><br \/>\nThe problem with using Write-Host to convey results is that they go directly to a display. \u00a0That means that they can&#8217;t be used by another script to automate a larger task. \u00a0Whenever you write a script, you are addressing a particular problem at hand <strong>and<\/strong> you are putting a tool in your toolbox that can be used to solve larger problems down the road. \u00a0If you use Write-Host to convey results, you have a useless tool in your toolbox.<\/p>\n<p>The correct cmdlet to use is <a title=\"Using the Write-Output Cmdlet\" href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh849921.aspx\" target=\"_blank\" rel=\"noopener\">Write-Output<\/a>. \u00a0Using Write-Output will display the results to the screen when you run you script by itself but, it will also allow your script to be used in a pipeline (or foreach loop) and have the results used by other scripts\/cmdlets.<\/p>\n<p><strong>To convey comforting information to the use<\/strong>r (e.g. &#8220;I&#8217;m about to do this&#8221;).<br \/>\nThis is super useful thing to do (I wish more people did more of it) but it is critical that you do it in the write way. \u00a0What&#8217;s that saying about &#8220;the road to hell being paved with good intentions&#8221;? \u00a0If you use Write-Host to do this, you are paving a road to hell.PowerShell is about automation. \u00a0Show comforting information is often helpful the first couple of times you run a script but then after that, it because an annoyance. \u00a0When you use Write-Host, the user is not able to say when they want this information and when they don&#8217;t.<\/p>\n<p>The correct tool is the <a title=\"Using the Write-Verbose Cmdlet\" href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh849951.aspx\" target=\"_blank\" rel=\"noopener\">Write-Verbose<\/a> cmdlet. \u00a0This cmdlet allows the user to control whether they see the information or not by invoking your script with the -VERBOSE flag or not.Information sent to Write-Host goes directly to a UI with no ability to capture it for a later time. \u00a0If you read the <a title=\"About-Redirection Help\" href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh847746.aspx\" target=\"_blank\" rel=\"noopener\">About_Redirection<\/a> help, you&#8217;ll see that PowerShell gives you the ability to redirect various streams of information. \u00a0The following command will take the output stream of Test-Script and output it to the file o.txt:<\/p>\n<p>PS&gt; Test-Script | Out-File o.txt<\/p>\n<p>If Test-Script had verbose information and you did this:<\/p>\n<p>PS&gt; Test-Script -Verbose | Out-File o.txt<\/p>\n<p>The <em>verbose<\/em> stream would go to the screen and the <em>output<\/em> stream would go to the file. \u00a0Using PowerShell redirection, you can &#8220;redirect&#8221; the <em>verbose<\/em> stream (referred to as &#8220;4&#8221; for historical reasons) into the output stream (referred to as &#8220;1&#8221;) and then both sets of data will be captured into the file:<\/p>\n<p>PS&gt; Test-Script -Verbose 4&gt;&amp;1 \u00a0| Out-File o.txt<\/p>\n<p>The syntax is clearly not obvious but it is worth learning (or at least knowing about) because I can guarantee that you&#8217;ll have times when this is <strong>exactly<\/strong> the thing you need &#8211; <strong>but<\/strong>, if the script used Write-Host &#8211; it won&#8217;t work.<\/p>\n<p>So if Write-Host is almost always the wrong thing to use, you might wonder why it is there in the first place. \u00a0The answer is in the phrase &#8220;almost always&#8221;. \u00a0I often use Write-Host when I&#8217;m writing a throw away script or function. \u00a0It is much faster and simpler to use it than to use Write-Verbose and then specify -VERBOSE. \u00a0For a throw away script &#8211; it doesn&#8217;t matter. \u00a0The key is to throw it away! \u00a0If you don&#8217;t intend to throw it away, you shouldn&#8217;t use Write-Host. \u00a0I always know the scripts I&#8217;m going to throw away because they are named T.PS1.<\/p>\n<p>The other scenario to use Write-Host is when you really do want to generate a UX. \u00a0Write-Host has a number of nice features like the the ability to colorize text that are great to use when you really do intend to generate a UX. \u00a0For example outputting a graph or my personal favorite:<\/p>\n<p>PS&gt; \u00a0iex (New-Object Net.WebClient).DownloadString(&#8220;<a href=\"http:\/\/bit.ly\/e0Mw9w\" target=\"_blank\" rel=\"nofollow noopener\">http:\/\/bit.ly\/e0Mw9w<\/a>&#8220;)<\/p>\n<p>Cheers!<br \/>\nJeffrey<\/p>\n","protected":false},"excerpt":{"rendered":"<p>[2023 Update] \u00a0 I\u2019ve been meaning to update this for a while. \u00a0The advice in this post is no longer current. \u00a0A while ago we changed the implementation of Write-Host to being a wrapper on top of Write-Information. \u00a0Prior to &hellip; <a href=\"https:\/\/www.jsnover.com\/blog\/2013\/12\/07\/write-host-considered-harmful\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":234,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4,5],"tags":[],"class_list":["post-219","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","category-work"],"jetpack_featured_media_url":"https:\/\/www.jsnover.com\/blog\/wp-content\/uploads\/2013\/12\/write-host.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/posts\/219","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/comments?post=219"}],"version-history":[{"count":14,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/posts\/219\/revisions"}],"predecessor-version":[{"id":279,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/posts\/219\/revisions\/279"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/media\/234"}],"wp:attachment":[{"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/media?parent=219"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/categories?post=219"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jsnover.com\/blog\/wp-json\/wp\/v2\/tags?post=219"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}