{"id":53923,"date":"2009-04-21T23:15:00","date_gmt":"2009-04-21T23:15:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/04\/21\/hey-scripting-guy-windows-powershell-and-pipelining\/"},"modified":"2009-04-21T23:15:00","modified_gmt":"2009-04-21T23:15:00","slug":"hey-scripting-guy-windows-powershell-and-pipelining","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-windows-powershell-and-pipelining\/","title":{"rendered":"Hey, Scripting Guy! Windows PowerShell and Pipelining"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> <\/H2>\n<P>Hey, Scripting Guy! I have seen you refer to this term <I>pipeline<\/I> many times since you started writing Windows PowerShell articles. What is up with that? Why don&#8217;t you just store things in a variable and then walk through the contents of the variable when you are working with Windows PowerShell? This is the way that we did it in VBScript, and it has worked fine for almost a decade. Can you explain what is so great about a pipeline (other than for economically transporting large amounts of liquid materials over great distances)? <BR><BR>&#8211; YH<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hi YH,<\/P>\n<P>Ed here. And I&#8217;m bummed you stole my smart alec remark. One of my hobbies is woodworking. I enjoy making sawdust out in my woodworking shop. It is completely relaxing, and when I am finished with a piece of furniture, there is a real sense of pride and accomplishment. The skills I use in my shop are completely different from the kind of skills used to write a script or to write a book. It is a good way to relax. I have been playing around with wood since I was a kid, and therefore I have many years of experience in making things from wood. When I first started out, my dad showed me how to take two skinny boards and make one large board. You join the straightest side of each board, evenly spread glue on the freshly joined boards, and carefully put them in a set of clamps and tighten the clamps. You must do this both quickly and carefully as glue starts to harden in a few minutes (depending of course on the kind of glue you are using) and glue is slippery, meaning that it is easy for the boards to become misaligned. Both facts are a challenge for a 10-year-old boy. As I grew older my interest in woodworking continued, and I began watching a guy named Norm Abrams on the <A href=\"http:\/\/www.newyankee.com\/index.php\" target=\"_blank\">New Yankee Workshop<\/A> (Norm: If you are reading this, send e-mail to <A href=\"mailto:Scripter@Microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/A>, and I will send you an autographed copy of the Microsoft Press <A href=\"http:\/\/www.microsoft.com\/MSPress\/books\/authors\/auth9541.aspx\" target=\"_blank\">Windows PowerShell Script Guide<\/A> book.) Norm is my hero. I even wear a flannel shirt when I am making sawdust out in my shop. He introduced me to a tool called a <A href=\"http:\/\/en.wikipedia.org\/wiki\/Biscuit_joiner\" target=\"_blank\">plate joiner<\/A> that is used to put biscuits in a board. The main advantage of biscuits is that they help you align two boards when you are gluing two boards.<\/P>\n<P>YH, you asked about how to work with the pipeline, and this article is \u201cHey, Scripting Guy!\u201d and not \u201cHey, Woodworking Guy!\u201d So let&#8217;s start scripting.<\/P>\n<TABLE class=\"dataTable\" id=\"EMD\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\">This week we will be looking at the basics of Windows PowerShell. Windows PowerShell is installed by default on Windows 7 and Windows Server 2008 R2. It is an optional installation on Windows Server 2008 and a download for <A href=\"http:\/\/www.microsoft.com\/downloads\/details.aspx?displaylang=en&amp;FamilyID=c6ef4735-c7de-46a2-997a-ea58fdfcba63\">Windows Vista<\/A>, <A href=\"http:\/\/www.microsoft.com\/downloads\/details.aspx?displaylang=en&amp;FamilyID=6ccb7e0d-8f1d-4b97-a397-47bcc8ba3806\">Windows XP<\/A>, and <A href=\"http:\/\/www.microsoft.com\/downloads\/details.aspx?displaylang=en&amp;FamilyID=10ee29af-7c3a-4057-8367-c9c1dab6e2bf\">Windows Server 2003<\/A>. The <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/hubs\/msh.mspx\">Windows PowerShell Scripting Hub<\/A> is a good place to get started with Windows PowerShell.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>In the <B>SearchTextFileForSpecificWord.vbs<\/B> script, we create an instance of the <B>Scripting.FileSystemObject<\/B>, open the file, and store the resulting <B>textstream<\/B> object in the <B>file<\/B> variable. We then use the <B>Do\u2026Until\u2026Loop<\/B> statement to work our way through the <B>textstream<\/B> object. Inside the loop we read one line at a time from the <B>textstream<\/B>. As soon as we have a specific line, we use the <B>InStr<\/B> statement to see whether a specific word is found. If it is, we display the sentence on the screen. The <B>SearchTextFileForSpecificWord.vbs<\/B> script is seen here:<\/P><PRE class=\"codeSample\">filepath = &#8220;C:\\fso\\testFile.txt&#8221;\nword = &#8220;text&#8221;\nset fso = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)\nSet file = fso.OpenTextFile(filepath)<\/p>\n<p>Do Until file.AtEndOfStream\n line = file.ReadLine\n If InStr(line, word) Then\n  WScript.Echo line\n End If\nLoop\n<\/PRE>\n<P>This technique of using the <B>ReadLine<\/B> method is very efficient and is the recommended way to work with large files. The other way of reading content from a text file in VBScript is the <B>ReadAll<\/B> method. The problem with using the <B>ReadAll<\/B> method is that it stores the contents of a text file in memory. This is not a problem if the file is small, but for a very large file that it would consume a very large amount of memory. In addition to the memory consumption issue, if you plan on working with the file one line at a time, which is one of the main reasons for reading a text file, you now have to contrive artificial methods to work your way through the file. When we use the <B>ReadLine<\/B> method from the <B>TextStream<\/B> object, the process is similar to pipelining in Windows PowerShell. <\/P>\n<P>With Windows PowerShell, we do not have to write a script to do the same thing the <B>SearchTextFileForSpecificWord.vbs<\/B> does. We can, in fact, perform the operation in just three lines of&nbsp;code: <\/P><PRE class=\"codeSample\">PS C:\\&gt; $filepath = &#8220;C:\\fso\\TestFile.txt&#8221;\nPS C:\\&gt; $word = &#8220;text&#8221;\nPS C:\\&gt; Get-Content -Path $filepath | ForEach-Object {if($_ -match $word){$_}}\n<\/PRE>\n<P>When we run the commands, we are given the output shown here:<\/P><IMG height=\"104\" alt=\"Image of scriptlike commands being typed directly into the Windows PowerShell console\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/april\/hey0421\/hsg-04-21-09-01.jpg\" width=\"500\" border=\"0\"> \n<P>&nbsp;<\/P>\n<P>Before we get too far, let&#8217;s examine the <B>TestFile.txt<\/B> file. This will give us a better idea of what we are working with. The file is seen here:<\/P><IMG height=\"179\" alt=\"Image of the TestFile.txt file\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/april\/hey0421\/hsg-04-21-09-02.jpg\" width=\"495\" border=\"0\"> \n<P>&nbsp;<\/P>\n<P>The first two lines that were typed into the Windows PowerShell console assign string values to variables. This serves the same purpose as the first two lines of the <B>SearchTextFileForSpecificWord.vbs<\/B> script. The last line we typed in the Windows PowerShell console is actually two separate commands. The first one reads the contents of the text file. This is the same as creating an instance of the <B>Scripting.FileSystemObject<\/B>, opening the text file by using the <B>Do\u2026While\u2026Loop<\/B> construction, and then calling the <B>ReadLine<\/B> method. Here is the <B>Get-Content<\/B> command:<\/P><PRE class=\"codeSample\">Get-Content -Path $filepath<\/PRE>\n<P>The results of the <B>Get-Content<\/B> cmdlet are pipelined to the <B>ForEach-Object<\/B> cmdlet. The <B>ForEach-Object<\/B> cmdlet enables us to work inside the pipeline to examine individual lines as they come across the pipe. The variable <B>$_<\/B> is an automatic variable that is created when we are working with a pipeline. It is used to enable us to work with a specific item when it is located on the pipeline. In VBScript you use the <B>If\u2026Then\u2026End If<\/B> construction. In Windows PowerShell, we use an <B>If(\u2026){\u2026}<\/B> construction. The two serve the same purpose\u2014decision making. In VBScript the condition that is evaluated goes between the <B>If<\/B> and the <B>Then<\/B> statement. In Windows PowerShell, the condition that is evaluated goes between two parentheses. In VBScript the action that is taken when a condition is matched goes between the <B>Then<\/B> and the <B>End If<\/B> statements. In Windows PowerShell, the action that is matched goes between a pair of braces. <\/P>\n<P>In VBScipt we use the <B>Instr<\/B> function to look inside the sentence to see whether a match could be found. In Windows PowerShell, we use the <B>\u2013match<\/B> operator. In VBScript we use the <B>Wscript.Echo<\/B> command to display the matching sentence on the screen, and in Windows PowerShell we only need to call the <B>$_<\/B> variable and it is automatically displayed. <\/P>\n<P>Of course we do not have to use the <B>Get-Content<\/B> cmdlet if we do not want to, because Windows PowerShell has a cmdlet called <B>Select-String<\/B> that will look inside a text file and retrieve the matching lines of text. Our three lines of code, seen earlier, could therefore be shortened to this one-line command:<\/P><PRE class=\"codeSample\">PS C:\\&gt; Select-String -Path C:\\fso\\TestFile.txt -Pattern &#8220;text&#8221;<\/PRE>\n<P>The results of this command are shown here:<\/P><IMG height=\"104\" alt=\"Image of the Select-String cmdlet reading a file and searching content at the same time\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/april\/hey0421\/hsg-04-21-09-03.jpg\" width=\"500\" border=\"0\"> \n<P>&nbsp;<\/P>\n<P>One of the things we really like to do with Windows PowerShell is to use the formatting cmdlets. There are three formatting cmdlets that are especially helpful. They are listed here, in the reverse order in which I use them:<\/P>\n<TABLE class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Format-Wide<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Format-Table<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Format-List<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>Let&#8217;s consider using the <B>Format-Wide<\/B> cmdlet. <B>Format-Wide<\/B> is useful when you want to display a single property across multiple columns. This might be because you want to have a list of all process names that are currently running on the server. Such a command would resemble the following:<\/P><PRE class=\"codeSample\">PS C:\\&gt; Get-Process | Format-Wide -Property name \u2013AutoSize<\/PRE>\n<P>The first thing we do is use the <B>Get-Process<\/B> cmdlet to return all the processes that are running on the computer. We pipeline the process objects to the <B>Format-Wide<\/B> cmdlet. We use the <B>\u2013property<\/B> parameter to select the name of each process, and we use the <B>\u2013autosize<\/B> parameter to tell <B>Format-Wide<\/B> to use as many columns as possible in the Windows PowerShell console without truncating any of the process names. We can see the results of this command here:<\/P><IMG height=\"176\" alt=\"Image of the Format-Wide cmdlet displaying a single property\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/april\/hey0421\/hsg-04-21-09-04.jpg\" width=\"500\" border=\"0\"> \n<P>&nbsp;<\/P>\n<P>If we were interested in between two and four properties from the processes, we could use the <B>Format-Table<\/B> cmdlet. The command might resemble the following:<\/P><PRE class=\"codeSample\">PS C:\\&gt; Get-Process | Format-Table -Property Name, Path, Id \u2013AutoSize<\/PRE>\n<P>We use the <B>Get-Process<\/B> cmdlet and pipeline the processes to the <B>Format-Table<\/B> cmdlet. We select three properties from the process objects: name, path and Id. The <B>Format-Table<\/B> cmdlet has an <B>\u2013autosize<\/B> parameter exactly as the <B>Format-Wide<\/B> cmdlet does. This helps arrange the columns in such a way that we do not waste space inside the console. As shown in the following image, because of the length of some paths to process executables, the <B>\u2013autosize<\/B> parameter had no effect in this example. As a best practice I always include the parameter when I am unsure of what the output will actually resemble. <\/P><IMG height=\"418\" alt=\"Image of using the Format-Table cmdlet to make a table\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/april\/hey0421\/hsg-04-21-09-05.jpg\" width=\"500\" border=\"0\"> \n<P>&nbsp;<\/P>\n<P>The format cmdlet I use the most is the <B>Format-List<\/B> cmdlet. This is because it is the best way to display lots of information. It is also a good way to see what kind of data might be returned by a particular command. Armed with this information, I then determine whether I want to focus on a more select group of properties and perhaps output the data as a table or just leave it in a list. When you use the <B>Format-List<\/B>, I will usually use the wildcard <B>*<\/B> to select all the properties from the objects. Here is an example of obtaining all the property information from all our processes:<\/P><PRE class=\"codeSample\">PS C:\\&gt; Get-Process | Format-List -Property *<\/PRE>\n<P>We will be unable to show you a picture of all the data that is returned by this command. This is because there is too much information to fit on a single screen. A small sampling of the information is shown here:<\/P><IMG height=\"427\" alt=\"Image of the process information displayed by the Get-Process cmdlet\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/april\/hey0421\/hsg-04-21-09-06.jpg\" width=\"500\" border=\"0\"> \n<P>&nbsp;<\/P>\n<P>There is so much information that all the properties and their values for a single process will not fit on a single screen. When you work with the <B>Format-List<\/B> cmdlet, if you want to look through all the data, you can pipeline the information to more. This works in the same manner as it did in the old command shell. If we were to use shortcut names (also known as aliases), we have a very compact command at our disposal. As shown here, <B>gps<\/B> is an alias for the <B>Get-Process<\/B> cmdlet. The <B>fl<\/B> command is an alias for <B>Format-List<\/B>. Because the first parameter of the <B>Format-List<\/B> cmdlet is the <B>\u2013property<\/B> parameter, we can leave it out and not type it. We then pipeline the results to <B>more<\/B>, which will cause the information to be displayed one page at a time. This is shown here:<\/P><PRE class=\"codeSample\">PS C:\\&gt; gps | fl * | more<\/PRE>\n<P>This concludes our look today at pipelining. As you have undoubtedly seen, the ability to pipeline the results of one command into another command provides us with powerful alternatives to storing everything in a variable. These techniques are not only for working interactively at the command line, but also are best practices when you write scripts. We will continue our discussion of Windows PowerShell basics tomorrow. Until then, take care.<\/P>\n<P>&nbsp;<\/P>\n<P><B>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/B><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have seen you refer to this term pipeline many times since you started writing Windows PowerShell articles. What is up with that? Why don&#8217;t you just store things in a variable and then walk through the contents of the variable when you are working with Windows PowerShell? This is the way [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[51,3,4,45],"class_list":["post-53923","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-getting-started","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I have seen you refer to this term pipeline many times since you started writing Windows PowerShell articles. What is up with that? Why don&#8217;t you just store things in a variable and then walk through the contents of the variable when you are working with Windows PowerShell? This is the way [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/53923","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=53923"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/53923\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=53923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=53923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=53923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}