Building PowerShell Functions that Support Pipeline Input

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys it's Trevor coming to you with another video and today we are going to talk about how to build PowerShell functions that support pipelining so as you're probably familiar with different shell environments allow you to take the output from one command and pipe that into another command for some additional processing so you can build these complex pipelines and you know create very complex sets of commands that run one after the other some people call them one-liners but the idea is that basically you can declare all your commands in kind of a long string and that data starts on the left and it just keeps going down the pipeline from command to command and of course PowerShell supports pipelining just like other shells such as bash so the key difference that you need to be aware of with PowerShell pipelining versus you know traditional pipelining and other shells like text oriented shells like bash for example is that in PowerShell we are dealing with objects instead of just mere text so it's important to think about each item that's going through your pipeline as being an object so what we're gonna do is we're going to explore how to build a powershell function and then how to specifically add a pipelining support into that function so let's go ahead and start by just declaring a function so we'll call this say hello and inside the function body we're just going to say write output input object hello so if we I need I need to hit control km to change my language mode to powershell here that's why I wasn't getting the syntax highlighting and the validation and all that stuff so now I've got this function say hello and if I hit f5 it's just gonna run it it's gonna declare the function in my global scope and it'll be available for me to run right so I can come over here and just do say hello and we get hello as our output from the function but what if I wanted to be able to say a bunch of different phrases and type those into the command and the command is only responsible for you're outputting whatever was piped into it so what we could do is take this hello string and pipe it into say hello but this hello in our function is currently hard-coded into the function so every time we run that function it's just gonna output hello so how do we take this input to the function and make it parameterised so that this text is whatever is piped in right so what we can do is convert this function from a basic function to an advanced function and the way that you do that in PowerShell is using what's called the command tlit binding attribute now when you add the command --let binding attribute you also are required to have a parameter block so even if you don't plan on adding any parameters to your function which we are in this case but even if you're not going to add any function parameters then command Labine ding does require you to have an empty parameter block so as you can see if I take out that parameter block it starts to complain if I hover over and look at that message it says hey it's an unexpected attribute command binding and of course it fixes itself when I add the parameter block right so that step number one is to take that basic function and convert it to an advanced function but there's something else at play here that isn't necessarily obvious especially if you're new to powershell and building powershell functions and that is the concept of three three different blocks inside of your powershell functions so there's a begin block a process block and an end block and basically each of those blocks is executed at different stages of the PowerShell pipeline so when you declare a function the way that we have it here right now so I basically just have you know inside the function body I've got my command lit binding and my parameter block and then anything that comes after the parameter block is considered the functions body but if we actually explore this function a little bit I'm gonna come over here to my interactive window actually no I'm not sorry I'm gonna do get command a - name say hello and basically what I'm doing by calling get command is I'm retrieving a reference to the say hello function that I have declared in the global scope so on the right here in my output you can see I've got this command this function object unfortunately I can't see all of the parameters so what I'm gonna do is do format list and tell it to spit out all of the properties of that function object so I'm actually using the pipeline here to say get me my function object and then pipe it into this formatting command that just changes how PowerShell displays that object that's being piped into it out to the console so if I hit f8 on line number 8 there it'll run that and we can now see all of the detailed information about my function now what you'll notice here is that we have a bunch of different properties that represent the function we have the name property so that's of course just the functions name PowerShell also breaks the function name down into the verb and then the noun because by convention PowerShell functions typically our verb - noun they don't have to be it's not strictly enforced but it is recommended and PowerShell actually you know breaks down those those components here and you also see that we have the definition and the script block so let's go ahead and assign the results of this get command command to a variable and that'll make it a little bit easier to explore so I'm basically going to get my function and store it in this command variable because that'll allow us to explore the child properties like script block in definition which are actually complex objects in and of themselves so if we take a look at the definition here the definition as you can see here is a string so it's going to return us a string value to us so let's go ahead and hit f8 and sure enough we just get a string that represents the body of this function however let's go over to command dot script block now the script block is going to look like a string similar to the definition but when we retrieve the script block we're actually getting back what's called the PowerShell script block object and we can explore that in a bit more detail as well so I'm going to do format list property star again so that we can see all of the components it's actually not listing out there so let me do select star okay so doing the select object properties star is a little bit better here so this is actually going to show us all of the different parameters here I'm actually just going to do a quick clear and then rerun that so as you can see we have this script block object and we have this thing called the abstract syntax tree that allows us to drill down even further within that object so let's grab the ast and you can see that we basically have this body extent and parent so we're getting get down into the weeds a little bit but what I wanted to point out is that we actually have a few different components to the function body we have the begin process and end block so let's go ahead and drill into the body here and so now as we are drilling into the function script block abstract syntax tree which is kind of a representation of the script blocks structure and then the body property you can now see the individual components that make up this particular script block so here we've got the begin block which is empty the process block which is also empty and the end block which has the contents of our function body here so that write output command is actually being assigned to what's called the end block and just for reference this body object is actually a script block in itself so there's a little bit of Inception like stuff going on here where we have a you know a script block that's part of a script block but it's part of its abstract syntax tree don't worry too much about the details here the key takeaway is that you have a begin process and end and when you declare a function and you don't explicitly declare the begin process and end blocks in the function as you can see here by default your function body is only going to be assigned to the end block of the function and what that means is that because we don't have a process block we can't pipe in information into the function and use the iteration capability that's built into PowerShell advanced functions so what we're actually gonna do is change the function to explicitly call out a begin process and end block and then once we've declared those blocks what we're gonna do is specify an input parameter we're gonna map the pipeline input to that parameter and then we're going to use that process block to iterate over each of the items in the array or in the in the pipeline input so let's go ahead and just declare a parameter here called message and the message parameter is going to contain it's going to basically map to the pipeline input and how do we do that well there is a parameter attribute called parameter and then inside the parameter attribute you'll have a property called value from pipeline and so value from pipeline is basically going to take whatever is in the pipeline and it's going to map it specifically to this parameter and we're going to set that property to true in this parameter attribute so now we are set up in this function to accept input from the pipeline and it'll get mapped to that message parameter so in theory you would think hey we can just change the message that we're printing out and that should work right so let's go ahead and try that so I've updated my function declaration and sure enough it looks like it's working okay we've passed that message input from the pipeline and we print out the hello message to the console here right so let's try that with an array so let's say we have two different messages that we want to print separately to the pipeline so hello and Trevor so those are two strings in an array and we're going to pipe that array into the function so what is the output that we get well this is not quite what we were expecting right we would have expected hello to get printed out and then on a new line we would have expected Trevor to get printed out but unfortunately what happened here is only Trevor got printed out and that's because only the end block of our function was actually defined as we looked at earlier so what do we have to do to fix this well inside of your power shell function body you can actually define a begin block a process block and an end block so you can actually do this explicitly or you can just do the implicit form which is to leave these out and your function body gets mapped to the end block as we discussed earlier and you can see now that I've explicitly declared those begin process and end blocks I'm actually getting this error saying unexpected closing curly brace and that's because I have a power shell statement here that should be inside one of those blocks but it's not so I now have to explicitly move that into the block that I want it to be in and now everything validates okay however when you're piping content in an array into a function and you want to iterate over that array and process the data you need to put your function body into the process block so begin is going to get called once when that function is initially invoked the process block is going to iterate once for each object in the array that's being piped into the function and then the end block after it's finished is going to finish so you can use that for things like doing counters for example or writing you know progress messages to initialize your progress and then send like a completion message or something like that there's a bunch of different use cases for why you would want to do that but for the time being let's just keep it simple and take a look at how to use the process block now inside the process block when you're using pipe pipelined input like we are here there is what's called an automatic variable in powershell called inputs so what you can do is do get help on about automatic variables try to do tab completion looks like it's not going to work let me try that it looks like the help system is broken still yeah well we'll talk about that later or you can actually just view it in a web browser as well you can just google for the documentation on that but basically just know that there is a special variable called input and that variable is accessible just inside the process block when you are piping input in so all we have to do is make sure that that write output statement is moved from the end block into our process block of our function and that we change the variable to input and you'll you'll notice that it's not actually message in this case because message refers to all of the parameter input not just the current item so let's go ahead and just run this we'll hit f5 here and of course I still have my get help command which should not be in there but what you'll notice here is that the function output hello and then Trevor so this is actually demonstrating that our pipelining is working correctly so we have this array that contains two strings we're piping it into the say hello function and then the say hello function is taking that message parameter it's mapping it to this special variable called input and we're processing that data in this case we're just omitting it to a standard output here but we're doing some processing on that data on a per object basis so let's go ahead and just kind of demonstrate what it looks like if you were to add a begin and end block here so I'll do write output beginning the processing function and then I'll copy that line and paste it down here in the end block and I'll just change this to ending the processing function so let's go ahead and hit f5 to run this again and you'll see now the output so the begin block in our function runs and then we iterate over each item on the pipeline input using that process block and then finally in the end block here is where it runs the end block and it just finishes the function that's where that's kind of the overall processing flow of a PowerShell advanced function so yeah that was really just the main goal of this video is to show you kind of the different components of a PowerShell advanced function and by doing so demonstrating to you how to implement pipeline input for your PowerShell functions so I hope you like this video if you did leave it a thumbs up that helps encourage me to create more content like this in the future check out my patreon page if you would like to financially support this channel and make sure that you smash that subscribe button and get notified about new videos when they are published out to my channel so thanks for watching I appreciate your support and please share this with your friends just helps get more visibility and let me know in the comments what other kind of videos you would like to see in the future Cheers you
Info
Channel: Trevor Sullivan
Views: 2,769
Rating: 4.8064518 out of 5
Keywords: Microsoft, PowerShell, DevOps, Automation, Scripting, Administrator, Pipeline
Id: BdfVsoMVz8g
Channel Id: undefined
Length: 18min 27sec (1107 seconds)
Published: Thu Jan 31 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.