{"id":76271,"date":"2016-01-12T16:01:00","date_gmt":"2016-01-12T16:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2016\/01\/12\/incorporating-pipelined-input-into-powershell-functions\/"},"modified":"2019-02-18T09:20:18","modified_gmt":"2019-02-18T16:20:18","slug":"incorporating-pipelined-input-into-powershell-functions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/incorporating-pipelined-input-into-powershell-functions\/","title":{"rendered":"Incorporating Pipelined Input into PowerShell Functions"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft MVP, Adam Bertram, talks about accepting pipelined input into Windows PowerShell advanced functions.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Today Microsoft MVP, Adam Bertram, returns to talk about accepting pipeline input into advanced Windows PowerShell functions.<\/p>\n<p align=\"left\">Note&nbsp;&nbsp;&nbsp;This is the second post in a series. Don&rsquo;t miss <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/introduction-to-advanced-powershell-functions\/\" target=\"_blank\">Introduction to Advanced PowerShell Functions<\/a>.<\/p>\n<p>When you begin to learn Windows PowerShell, you&#039;ll soon find yourself neck-deep in objects. Objects are one of the fundamental concepts of what makes PowerShell so user-friendly&mdash;and powerful at the same time.<\/p>\n<p>As you dive deeper into the language, the next concept that you&#039;ll typically stumble over is the pipeline. So let&#039;s take your PowerShell skills to the next level by incorporating pipeline input abilities into your advanced functions!<\/p>\n<p>The pipeline is what makes PowerShell so unique. The thought of a pipeline is not new. We&#039;ve been able to pipe strings from the output of one command to the input of another command for a long time. However, it wasn&#039;t until PowerShell came along that we had a language that allowed us to pipe objects from one command to another.<\/p>\n<p>The following is a very basic advanced function called <b>Get-Something<\/b> with a single parameter called <b>$item<\/b>. When called, this function simply outputs a sentence to the console that states whatever value of <b>$item<\/b> is passed to the function:<\/p>\n<p style=\"margin-left:30px\">Function Get-Something {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Param($item)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &quot;You passed the parameter $item into the function&quot;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>For a function to accept pipeline input, it needs to be an advanced function. Maybe that&#039;s all it needs. I hope!<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/p1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/p1.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Nope. Not only did the <b>$item<\/b> parameter not have a value, but I also got an error message about some input object that cannot be bound to something. I suppose making a function advanced isn&#039;t quite the whole story for here. Fear not. The journey required to get us where we need to go is a short one. Read on&hellip;<\/p>\n<p>To get the value <b>abc123<\/b> to represent the <b>$item<\/b> variable in our function, PowerShell has to know how to match the value to the <b>$item<\/b> parameter. This is done through a process called parameter binding. Parameter binding is the selection process that goes on whenever an advanced function or a compiled cmdlet sees something coming from the pipeline. During this process, it tries to match which parameter (the only one in our case) to bind to our <b>abc123<\/b> value.<\/p>\n<p>To set up the function for this parameter binding process, I need to smarten the <b>$item<\/b> parameter a bit by using the <b>Parameter<\/b> keyword instead of simply throwing <b>$item<\/b> in between the <b>Param<\/b> parentheses. This allows me to add parameter attributes to the <b>$item<\/b> parameter. Among those are two attributes directly related to accepting pipeline input: <b>ValueFromPipeline<\/b> and <b>ValueFromPipelineByPropertyName<\/b>.<\/p>\n<p>This will make the function look something like this:<\/p>\n<p style=\"margin-left:30px\">Function Get-Something {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Param(<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter()]<\/p>\n<p style=\"margin-left:30px\">$item<\/p>\n<p style=\"margin-left:30px\">)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &quot;You passed the parameter $item into the function&quot;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>When the <b>Parameter<\/b> keyword is representing <b>$item<\/b>, there is a spot to place the first parameter attribute called <b>ValueFromPipeline<\/b>:<\/p>\n<p style=\"margin-left:30px\">Function Get-Something {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Param(<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipeline)]<\/p>\n<p style=\"margin-left:30px\">$item<\/p>\n<p style=\"margin-left:30px\">)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &quot;You passed the parameter $item into the function&quot;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>The <b>ValueFromPipeline<\/b> keyword finally allows passing the <b>abc123<\/b> value directly to the <b>Get-Something<\/b> function:<\/p>\n<p style=\"margin-left:30px\">PS&gt; &#039;abc123&#039; | Get-Something<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter abc123 into the function<\/p>\n<p>This is great! But maybe I want to pass Windows service names to my function and output their names in the sentence:<\/p>\n<p style=\"margin-left:30px\">PS&gt; Get-Service | Get-Something<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter System.ServiceProcess.ServiceController into the function<\/p>\n<p>Huh? I was expecting it to look something like this with each service represented by <b>$item<\/b>:<\/p>\n<p style=\"margin-left:30px\">You passed the parameter Application Identity into the function<\/p>\n<p style=\"margin-left:30px\">You passed the parameter DHCP Client into the function<\/p>\n<p style=\"margin-left:30px\">You passed the parameter DNS Client into the function<\/p>\n<p>Sorry. Work is never done, right? We need to add a little bit more code.<\/p>\n<p>The reason this happens is because the <b>ValueFromPipeline<\/b> keyword binds entire objects to the parameter. The service name is simply a property of the object type System.ServiceProcess.ServiceController.<\/p>\n<p>When I piped <b>abc123<\/b> to <b>Get-Something<\/b>, that was a simple string. <b>Get-Service<\/b> is sending a more complicated object to the function now and <b>Get-Something<\/b> doesn&#039;t know how to handle it. I need a way to bind only a single property of the System.ServiceProcess.ServiceController objects that <b>Get-Service<\/b> outputs.<\/p>\n<p>To do this, I can&#039;t use <b>ValueFromPipeline<\/b>. Instead, I need to use a similar (yet way too long keyword) called <b>ValueFromPipelineByPropertyName<\/b> in its place:<\/p>\n<p style=\"margin-left:30px\">Function Get-Something {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Param(<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName)]<\/p>\n<p style=\"margin-left:30px\">$item<\/p>\n<p style=\"margin-left:30px\">)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &quot;You passed the parameter $item into the function&quot;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>However, if you leave the function as-is and try to pipe <b>Get-Service<\/b> directly to <b>Get-Something<\/b>, you&#039;ll soon be in for a lot of nasty, red error text.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3755.p2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3755.p2.png\" alt=\"Image of error message\" title=\"Image of error message\" \/><\/a><\/p>\n<p>Why? Because PowerShell still doesn&#039;t know how to bind those objects from <b>Get-Service<\/b> to the function. I need to change the parameter&#039;s name to match the object property I&#039;d like to accept input from. In this case, each System.ServiceProcess.ServiceController object that <b>Get-Service<\/b> outputs has a <b>Name<\/b> property that I&#039;d like to show up in the sentence output.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/p3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/p3.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Let&#039;s change the parameter name to <b>$Name<\/b> and see what happens:<\/p>\n<p style=\"margin-left:30px\">Function Get-Something {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Param(<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName)]<\/p>\n<p style=\"margin-left:30px\">$Name<\/p>\n<p style=\"margin-left:30px\">)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &quot;You passed the parameter $Name into the function&quot;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">PS&gt; Get-Service | Get-Something<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter mylastservice into the function<\/p>\n<p>Odd. It only output the Windows service &quot;mylastservice.&quot; Why not all of them?<\/p>\n<p>It&#039;s because, by default, it will only output the very last object in the pipeline. To process each object output by <b>Get-Service<\/b>, I need to include the <b>Write-Host<\/b> line in a process block.<\/p>\n<p>Any code inside a process block is run for each object coming from the pipeline&mdash;not only the last one. To process all objects, I&#039;ll add one of these process blocks inside of the function:<\/p>\n<p style=\"margin-left:30px\">Function Get-Something {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Param(<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(ValueFromPipelineByPropertyName)]<\/p>\n<p style=\"margin-left:30px\">$Name<\/p>\n<p style=\"margin-left:30px\">)<\/p>\n<p style=\"margin-left:30px\">process {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host &quot;You passed the parameter $Name into the function&quot;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">PS&gt; Get-Service | Get-Something<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter service1 into the function<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter service2 into the function<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter service3 into the function<\/p>\n<p style=\"margin-left:30px\">PS&gt; You passed the parameter service4 into the function<\/p>\n<p>Much better! You can now see that the name of each service is being successfully passed into the sentence string and being output to the console by <b>Write-Host<\/b>. You now have a function that you can pass objects or object properties to.<\/p>\n<p>If you got some value from this information and would like to dive deeper into PowerShell, the pipeline, advanced functions, and modules, be sure to check out my Pluralsight course about building advanced PowerShell functions and modules. I&#039;ll take you into a way deep dive about advanced functions and modules.<\/p>\n<p>~Adam<\/p>\n<p>Thank you very much for these two awesome posts, Adam. Join me tomorrow for more cool Windows PowerShell stuff.&nbsp;<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft MVP, Adam Bertram, talks about accepting pipelined input into Windows PowerShell advanced functions. Microsoft Scripting Guy, Ed Wilson, is here. Today Microsoft MVP, Adam Bertram, returns to talk about accepting pipeline input into advanced Windows PowerShell functions. Note&nbsp;&nbsp;&nbsp;This is the second post in a series. Don&rsquo;t miss Introduction to Advanced PowerShell Functions. When [&hellip;]<\/p>\n","protected":false},"author":597,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-76271","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft MVP, Adam Bertram, talks about accepting pipelined input into Windows PowerShell advanced functions. Microsoft Scripting Guy, Ed Wilson, is here. Today Microsoft MVP, Adam Bertram, returns to talk about accepting pipeline input into advanced Windows PowerShell functions. Note&nbsp;&nbsp;&nbsp;This is the second post in a series. Don&rsquo;t miss Introduction to Advanced PowerShell Functions. When [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/76271","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\/597"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=76271"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/76271\/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=76271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=76271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=76271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}