1. Trang chủ >
  2. Công Nghệ Thông Tin >
  3. Kỹ thuật lập trình >

1 The pipeline: enabling power with less typing

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (9.65 MB, 367 trang )


98



CHAPTER 9



The pipeline, deeper



Figure 9.1 Creating a text file

containing computer names,

with one name per line



That’s the command that produces something. The second command will be Command B, which needs to accept Command A’s output and then do its own thing.

PS C:\> CommandA | CommandB



For example, suppose you have a text file that contains one computer name on each

line, as shown in figure 9.1.

You might want to use those computer names as the input to some command, telling that command which computers you want it to run against. Consider this example:

PS C:\> Get-Content .\computers.txt | Get-Service



When Get-Content runs, it places the computer names into the pipeline. PowerShell

then has to decide how to get those to the Get-Service command. The trick with

PowerShell is that commands can only accept input on a parameter. That means

PowerShell has to figure out which parameter of Get-Service will accept the output

of Get-Content. This figuring-out process is called pipeline parameter binding, and it’s

what we’ll be covering in this chapter. PowerShell has two methods it can use to get

the output of Get-Content onto a parameter of Get-Service. The first method the

shell will try is called ByValue; if that doesn’t work, it’ll try ByPropertyName.



9.3



Plan A: pipeline input ByValue

With this pipeline parameter binding method, PowerShell looks at the type of object

produced by Command A and tries to see if any parameter of Command B can accept

that type of object from the pipeline. You can determine this for yourself: first, pipe

the output of Command A to Get-Member, to see what type of object Command A is

producing. Then, examine the full help of Command B (for example, Help

Get-Service -full) to see if any parameter accepts that type of data from the pipeline ByValue. Figure 9.2 shows what you might discover.

What you’ll find is that Get-Content produces objects of the type System.String

(or String for short). You’ll also find that Get-Service does have a parameter that



www.it-ebooks.info



Plan A: pipeline input ByValue



Figure 9.2



99



Comparing the output of Get-Content to the input parameters of Get-Service



accepts String from the pipeline ByValue. The problem is that it’s the -Name parameter, which according to the help “specifies the service names of services to be

retrieved.” That isn’t what we wanted—our text file, and therefore our String objects,

are computer names, not service names. If we ran the following,

PS C:\> Get-Content .\computers.txt | Get-Service



we’d be attempting to retrieve services named SERVER2, WIN8, and so forth, which is

probably not going to work.

PowerShell only permits one parameter to accept a given type of object from the

pipeline ByValue. This means that because the -Name parameter accepts String from

the pipeline ByValue, no other parameter can do so. That dashes our hopes for trying

to pipe computer names from our text file to Get-Service.

In this case, pipeline input is working, but it isn’t achieving the results we’d hoped

for. Let’s consider a different example, where we do get the results we want. Here’s

the command line:

PS C:\> get-process -name note* | Stop-Process



www.it-ebooks.info



100



CHAPTER 9



Figure 9.3



The pipeline, deeper



Binding the output of Get-Process to a parameter of Stop-Process



Let’s pipe the output of Command A to Get-Member and examine the full help for

Command B. Figure 9.3 shows what you’ll find.

Get-Process produces objects of the type System.Diagnostics.Process (note

that we limited the command to processes whose names start with note*; we made sure

a copy of Notepad was running so that the command would produce some output).

Stop-Process can accept those Process objects from the pipeline ByValue; it does so

on its -InputObject parameter. According to the help, that parameter “stops the processes represented by the specified process objects.” In other words, Command A will

get one or more Process objects, and Command B will stop (or kill) them.

This is a good example of pipeline parameter binding in action, and it also illustrates an important point in PowerShell: For the most part, commands sharing the

same noun (as Get-Process and Stop-Process do) can usually pipe to each other

ByValue.

Let’s cover one more example:

PS C:\> get-service -name s* | stop-process



www.it-ebooks.info



Plan A: pipeline input ByValue



Figure 9.4



101



Examining the output of Get-Service and the input parameters of Stop-Process



On the face of it, this might not seem to make any sense. But let’s see this through by

piping Command A’s output to Get-Member, and re-examining the help for Command

B. Figure 9.4 shows what you should find.

Get-Service produces objects of the type ServiceController (technically, System

.ServiceProcess.ServiceController, but you can usually take the last bit of the

TypeName as a shortcut). Unfortunately, there isn’t a single parameter of Stop-Process

that can accept a ServiceController object. That means the ByValue approach has

failed, and PowerShell will try its backup plan: ByPropertyName.



www.it-ebooks.info



102



9.4



CHAPTER 9



The pipeline, deeper



Plan B: pipeline input ByPropertyName

With this approach, you’re still looking to attach the output of Command A to parameters of Command B. But ByPropertyName is slightly different than ByValue. With this

backup method, it’s possible for multiple parameters of Command B to become

involved. Once again, pipe the output of Command A to Get-Member, and then look at

the syntax for Command B. Figure 9.5 shows what you should find: The output of Command A has one property whose name corresponds to a parameter on Command B.

A lot of folks will overthink what’s happening here, so let’s be clear on how simple

the shell is being: it’s literally looking for property names that match parameter

names. That’s it. Because the property “Name” is spelled the same as the parameter

“-Name,” the shell will try to connect the two.



Figure 9.5



Mapping properties to parameters



www.it-ebooks.info



Plan B: pipeline input ByPropertyName



103



But it can’t do so right away: first it needs to see if the -Name parameter will accept

input from the pipeline ByPropertyName. A glance at the full help, shown in

figure 9.6, is required to make this determination.

In this case, -Name does accept pipeline input ByPropertyName, so this connection

will work. Now, here’s the trick: unlike ByValue, where only one parameter would be

involved, ByPropertyName will connect every matching property and parameter (provided each parameter has been designed to accept pipeline input ByPropertyName).



Figure 9.6



Checking to see if Stop-Process’s -Name parameter accepts pipeline input ByPropertyName



www.it-ebooks.info



104



CHAPTER 9



Figure 9.7



The pipeline, deeper



Attempting to pipe Get-Service to Stop-Process



In the case of our current example, only Name and -Name match. The results? Examine

figure 9.7.

A bunch of error messages. The problem is that services’ names are usually things

like ShellHWDetection and SessionEnv, whereas the services’ executables might be

things like svchost.exe. Stop-Process only deals with those executable names. But

even though the Name property connects to the -Name parameter via the pipeline, the

values inside the Name property don’t make sense to the -Name parameter, which leads

to the errors.

Let’s look at a more successful example. Create a simple comma-separated values

(CSV) file in Notepad, using the example in figure 9.8.

Save the file as Aliases.csv. Now, back in the shell, try importing it, as shown in

figure 9.9. You should also pipe the output of Import-CSV to Get-Member, so that you

can examine the output’s members.



www.it-ebooks.info



Plan B: pipeline input ByPropertyName



Figure 9.8 Create this CSV file

in Windows Notepad.



Figure 9.9



Importing the CSV file and checking its members



www.it-ebooks.info



105



106



CHAPTER 9



Figure 9.10



The pipeline, deeper



Matching properties to parameter names



You can clearly see that the columns from the CSV file become properties, and each

data row in the CSV file becomes an object. Now, examine the help for New-Alias, as

shown in figure 9.10.

Both of the properties—Name and Value—correspond to parameter names of NewAlias. Obviously, this was done on purpose—when you create the CSV file, you can

name those columns anything you want. Now, check to see if -Name and -Value accept

pipeline input ByPropertyName, as shown in figure 9.11.

Both parameters do, meaning this trick will work. Try running the command:

PS C:\> import-csv .\aliases.csv | new-alias



The result will be three new aliases, named d, sel, and go, which point to the commands Get-ChildItem, Select-Object, and Invoke-Command, respectively. This is a

powerful technique for passing data from one command to another, and for accomplishing complex tasks in a minimum number of commands.



www.it-ebooks.info



When things don’t line up: custom properties



Figure 9.11



9.5



107



Looking for parameters that accept pipeline input ByPropertyName



When things don’t line up: custom properties

The CSV example was cool, but it’s pretty easy to make property and parameter names

line up when you’re creating the input from scratch. Things get tougher when you’re

forced to deal with objects that are created for you, or data that’s being produced by

someone else.

For this example, we’re going to introduce a new command that you might not

have access to: New-ADUser. It’s part of the ActiveDirectory module, which you’ll find

on any Windows Server 2008 R2 (or later) domain controller. You can also get that

module on a client computer by installing Microsoft’s Remote Server Administration

Tools (RSAT). But for now, don’t worry about running the command; follow along

with the example.

New-ADUser has a number of parameters, each designed to accept information

about a new Active Directory user. Here are some examples:

 -Name (this is mandatory)

 -samAccountName (technically not mandatory, but you have to provide it to



make the account usable)



www.it-ebooks.info



108



CHAPTER 9



The pipeline, deeper



 -Department

 -City

 -Title



We could cover the others, but let’s work with these. All of them accept pipeline input

ByPropertyName.

For this example, we’ll again assume you’re getting a CSV file, but it’s coming from

your company’s Human Resources or Personnel department. You’ve given them your

desired file format a dozen times, but they persist in giving you something that’s close,

but not quite right, as shown in figure 9.12.



Figure 9.12 Working with

the CSV file provided by

Human Resources



As you can see in figure 9.12, the shell can import the CSV file fine, resulting in three

objects with four properties apiece. The problem is that the dept property won’t line

up with the -Department parameter of New-ADUser, the login property is meaningless, and you don’t have samAccountName or Name properties—both of which are

required if you want to be able to run this command to create new users:

PS C:\> import-csv .\newusers.csv | new-aduser



How can you fix this? Obviously, you could open the CSV file and fix it, but that’s a lot

of manual work over time, and the whole point of PowerShell is to reduce manual

labor. Why not set up the shell to fix it instead? Look at the following example:

PS C:\> import-csv .\newusers.csv |

>> select-object -property *,

>> @{name='samAccountName';expression={$_.login}},

>> @{label='Name';expression={$_.login}},

>> @{n='Department';e={$_.Dept}}

>>

login



: DonJ



www.it-ebooks.info



Xem Thêm
Tải bản đầy đủ (.pdf) (367 trang)

×