Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Learn PowerShell Scripting in a Month of Lunches: use PowerShell how it wants to be used

2,412 views

Published on

In Learn PowerShell Scripting in a Month of Lunches, you'll discover how scripting is different from command-line PowerShell, as you explore concrete hands-on examples. You'll master good habits for elegant, efficient, and error-free scripting along with best practices and easy-to-digest tips that any professional PowerShell scripter needs to know. You'll also get to grips with the process of developing, testing, and deploying scripts and tackle the art of PowerShell toolmaking.

Save 42% off with code sljones at: https://www.manning.com/books/learn-powershell-scripting-in-a-month-of-lunches

Published in: Software
  • Be the first to comment

Learn PowerShell Scripting in a Month of Lunches: use PowerShell how it wants to be used

  1. 1. Parameter Binding and the PowerShell Pipeline Save 42% off Learn PowerShell Scripting in a Month of Lunches with code sljones at manning.com.
  2. 2. The PowerShell Pipeline As you are likely aware, PowerShell has a strong ability to create highly reusable, context-independent tools, which it refers to as commands. Toolmaking is scripting these commands together to do wonderful things. To be a toolmaker is to understand the pipeline at its most basic level, and to create tools that leverage the pipeline. In this presentation we’re going to focus on the pipeline as something to write for, rather than to simply use.
  3. 3. The PowerShell Pipeline Take traditional pipeline behavior from shells like Bash and Cmd.exe. Mix in PowerShell’s unique object-oriented nature. Add a dash of Linux- style command parsing. The result? PowerShell’s pipeline, a fairly complex and deeply powerful tool for composing tools into administrative solutions.
  4. 4. Visualizing the Pipeline Grab a sheet of paper and a pen. Draw yourself something like this:
  5. 5. Visualizing the Pipeline Now, write some command names in those boxes. Maybe Get- Process in the first box, maybe ConvertTo-HTML in the second box, and perhaps Out-File in the third box. Get-Process ConvertTo-HTML Out-File
  6. 6. Visualizing the Pipeline The image on the previous slide is a good visual depiction of how PowerShell runs commands in the pipeline: as one command produces objects, they go into the pipeline one at a time, and get passed on to the next command. At the end of the pipeline, when there are no further commands, any objects in the pipeline are passed to PowerShell’s formatting system to be formatted for on-screen display. But how is PowerShell making this happen?
  7. 7. It’s all in the parameters PowerShell uses two methods to dynamically figure out how to get data – that is, objects – out of the pipeline and “into” a command. Both of these methods rely on the accepting command’s parameters. In other words – and this is important – the only way a command can accept data is via its parameters.
  8. 8. It’s all in the parameters This implies when you design a command, and you design its parameters, you are deciding how that command will accept information, including how it will accept information from the pipeline. This process is therefore not magic; it’s a science, and it’s decided in advance by whoever designed the command. Let’s take a closer look!
  9. 9. Plan A: ByValue PowerShell has a hardcoded preference to pass entire objects from the pipeline into a command. Because of that hardcoded preference, it will always attempt to do that before it tries to do anything else. In order to do so, the accepting command must: • Define a parameter that supports accepting pipeline input ByValue… • …and that parameter must be capable of accepting whatever type of object happens to be in the pipeline.
  10. 10. Plan A: ByValue Let’s run Get-Process from our exercise on slide 5. When we run Get-Process | Get-Member – the first line of output will contain the TypeName, which identifies the kind of object that the command produced. Turns out it’s a System.Diagnostics.Process object. What about the second command from slide 5?
  11. 11. Plan A: ByValue You’ll want to first make sure you’ve run Update-Help so that you have help files, and then run Help ConvertTo-HTML –ShowWindow so that you can explore the complete help. Do you see any parameters of the command that are capable of accepting a [Process] object? Probably not. However, you probably will see a parameter capable of accepting an [Object] (or [Object[]]).
  12. 12. Plan A: ByValue In the Microsoft .NET Framework, System.Object is like the mother type for everything else. That is, everything inherits from the Object type. In PowerShell, PSObject is more or less equivalent to Object. So, whenever you see that a parameter accepts PSObject, you know that it can accept basically anything. In ConvertTo-HTML, you’ll find an – InputObject parameter, which fulfills our two criteria: • It can accept pipeline input using the ByValue technique • It can accept objects of the type System.Diagnostics.Process, because it can accept the more-generic PSObject
  13. 13. Plan A: ByValue Therefore, PowerShell will take the output of Get-Process, and attach it to the –InputObject parameter of ConvertTo-HTML. Reading the help for the second command, that parameter “specifies the objects to be represented in HTML.” So, whatever you pipe into ConvertTo-HTML will be picked up, ByValue, by the –InputObject parameter, and will be “represented in HTML.” Try it yourself and see!
  14. 14. Introducing Trace-Command PowerShell actually has a way for you to see this passing-of-the-objects happening. It’s called Trace-Command, and it’s a really useful way for debugging pipeline parameter binding. It’ll show you, in detail, the decisions PowerShell is making, and the actions it’s attempting to take. To run the command, you’ll run something like Trace-Command –Name parameterbinding –Expression { Your command goes here } – PSHost. Keep in mind that your command will actually run, so you need to be careful not to run anything that could be damaging, like deleting a bunch of user accounts just to see what happens!
  15. 15. Tracing ByValue Parameter Binding Let’s go ahead and apply Trace-Command to our current example. Here’s the command we ran: PS C:> trace-command -Expression { get-process | convertto-html | [CA]out-null } -Name ParameterBinding –PSHost You’ll notice that we ended our command with Out-Null; we did that to suppress the normal output of ConvertTo-HTML, just to keep the output a little cleaner. You will, however, see PowerShell dealing with getting objects from ConvertTo-HTML into Out-Null, so it’s a useful illustration.
  16. 16. Tracing ByValue Parameter Binding You’ll first see PowerShell attempt to bind – that is, “attach” – any NAMED arguments for Get-Process. There weren’t any – we didn’t specify any parameters manually in our command. DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Process] PowerShell next looks for POSITIONAL parameters, which we also didn’t have.
  17. 17. Tracing ByValue Parameter Binding PowerShell then checks to make sure that all of the command’s MANDATORY parameters have been provided, and we pass that check. DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd lineargs [Get-Process] DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Get-Process] This whole process – named, positional, and then a mandatory check – repeats for the ConvertTo-HTML and Out-Null commands.
  18. 18. Tracing ByValue Parameter Binding There’s an important lesson in this: regardless of how a command is wired up to accept pipeline input, specifying named or positional parameters always takes precedence, because PowerShell binds those first. If we’d manually specified –InputObject, for example, then we’d have prevented the ByValue parameter binding from working, because we’d have “bound up” the parameter ourselves before ByValue was even considered. This is shown on the next slide.
  19. 19. Tracing ByValue Parameter Binding DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [ConvertTo-Html] DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [ConvertTo-Html] DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [ConvertTo-Html] DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Out-Null] DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Out-Null] DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Out-Null]
  20. 20. Tracing ByValue Parameter Binding The next thing that happens is PowerShell calling each of the three commands’ BEGIN code. Not all commands specify any BEGIN code, but PowerShell gives them all the opportunity. DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing Now, this next bit it a little surprising, because PowerShell is attempting to bind a pipeline object to a parameter of Out-Null. How the heck did anything even get into the pipeline at this point?
  21. 21. Tracing ByValue Parameter Binding Well, the previous command, ConvertTo-HTML, has clearly taken the opportunity to produce some output from its BEGIN code. Sneaky. Anyway, PowerShell now has to deal with that, even though the first command, Get-Process, hasn’t even run yet! DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Out-Null]
  22. 22. Tracing ByValue Parameter Binding This next bit is interesting. Here’s what you’ll see: • PowerShell identifies the type of object in the pipeline as a System.String. Take a minute and read the full help for Out-Null. Do you see any parameters capable of accepting a String from the pipeline using the ByValue method? DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.String] DEBUG: ParameterBinding Information: 0 : RESTORING pipeline parameter's original values
  23. 23. Tracing ByValue Parameter Binding PowerShell is about to discover that the –InputObject parameter of Out-Null accepts either Object or PSObject, and so it’s going to bind the output of ConvertTo-HTML to that –InputObject parameter. DEBUG: ParameterBinding Information: 0 : Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION DEBUG: ParameterBinding Information: 0 : BIND arg [<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">] to parameter [InputObject] DEBUG: ParameterBinding Information: 0 : BIND arg [<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">] to param [InputObject] SUCCESSFUL
  24. 24. Tracing ByValue Parameter Binding In fact, it appears to have accepted a couple of String objects from the pipeline. These look like header lines for an HTML file, which makes sense – ConvertTo-HTML probably gets these out of the way as “boilerplate” before it settles down to its real job. On the next slide, we see that the MANDATORY check on Out-Null succeeds, and we continue to deal with initial boilerplate issued by ConvertTo-HTML.
  25. 25. Tracing ByValue Parameter Binding DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Out-Null] DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Out-Null] DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.String] DEBUG: ParameterBinding Information: 0 : RESTORING pipeline parameter's original values DEBUG: ParameterBinding Information: 0 : Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION DEBUG: ParameterBinding Information: 0 : BIND arg [<html xmlns="http://www.w3.org/1999/xhtml">] to parameter [InputObject] DEBUG: ParameterBinding Information: 0 : BIND arg [<html xmlns="http://www.w3.org/1999/xhtml">] to param [InputObject] SUCCESSFUL
  26. 26. Tracing ByValue Parameter Binding OK, let’s get ahead of our selves a bit, past all the boilerplate “header” HTML. We’ll go down to the point where Get-Process actually runs, and where PowerShell recognizes the type of object it’s produced: DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [ConvertTo-Html] DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.Diagnostics.Process#HandleCount]
  27. 27. Tracing ByValue Parameter Binding Next we’ll see those Process objects being bound to the – InputObject parameter of ConvertTo-HTML: DEBUG: ParameterBinding Information: 0 : Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION DEBUG: ParameterBinding Information: 0 : BIND arg [System.Diagnostics.Process] to parameter [InputObject] DEBUG: ParameterBinding Information: 0 : BIND arg [System.Diagnostics.Process] to param [InputObject] SUCCESSFUL
  28. 28. Tracing ByValue Parameter Binding The trace output goes on, of course, but this is really what we were looking for: proof that PowerShell is doing what we expected. You’ll notice the phrase NO COERCION quite a bit in the preceding; that’s an indication that PowerShell was able to bind the output as-is, without trying to convert it to something else. Coercion is one of the things that can make pipeline parameter binding more confusing, and it’s what this trace output can help you see and understand. For example, PowerShell is capable of coercing, or converting, a number into a string, so that the resulting string can bind to a parameter that accepts String.
  29. 29. When ByValue Fails So that’s the ByValue story. But what if it fails? Go back to your paper diagram. Erase or cross-out ConvertTo- HTML and Out-Null, and in the second box, write Stop-Service. Don’t run the resulting command, yet – we need to talk about what happens.
  30. 30. When ByValue Fails We know that the first command produces Process objects. Examining its full help file, do you see any parameters of Stop- Service which will: • Accept pipeline input ByValue… • …and also accept input types of either Process, Object, or PSObject? We don’t see any parameters that fit the criteria, and so the ByValue method fails. Time for Plan B – but that’s a topic for a different day.
  31. 31. Get up to speed with PowerShell during your lunch break! Save 42% off Learn PowerShell Scripting in a Month of Lunches with code sljones at manning.com. Also see:

×