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

5 When things don’t line up: custom properties

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 )


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



When things don’t line up: custom properties

dept

city

title

samAccountName

Name

Department



:

:

:

:

:

:



IT

Las Vegas

CTO

DonJ

DonJ

IT



login

dept

city

title

samAccountName

Name

Department



:

:

:

:

:

:

:



GregS

Custodial

Denver

Janitor

GregS

GregS

Custodial



login

dept

city

title

samAccountName

Name

Department



:

:

:

:

:

:

:



109



JeffH

IT

Syracuse

Network Engineer

JeffH

JeffH

IT



That’s some pretty funky syntax, so let’s break it down:

 We used Select-Object and its -Property parameter. We started by specifying



the property *, which means “all of the existing properties.” Notice that the * is

followed by a comma, which means we’re continuing the list of properties.

 We then created a hash table, which is the construct starting with @{ and ending

with }. Hash tables consist of one or more key=value pairs, and Select-Object

has been programmed to look for some specific keys, which we’ll provide to it.

 The first key Select-Object wants can be Name, N, Label, or L, and the value for

that key is the name of the property we want to create. In the first hash table, we

specified samAccountName, in the second, Name, and in the third, Department.

These correspond to the parameter names of New-ADUser.

 The second key that Select-Object needs can be either Expression or E. The

value for this key is a script block, contained within {curly brackets}. Within that

script block, you use the special $_ placeholder to refer to the existing piped-in

object (the original row of data from the CSV file) followed by a period. $_ lets

you access one property of the piped-in object, or one column of the CSV file.

This specifies the contents for the new properties.

Go ahead and create the CSV file that’s shown in figure 9.12.

Then try running the exact command we did above—you can type it exactly

as shown.



TRY IT NOW



What we’ve done is taken the contents of the CSV file—the output of Import-CSV—

and modified it, dynamically, in the pipeline. Our new output matches what

New-ADUser wants to see, so we can now create new users by running this command:

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



www.it-ebooks.info



110



CHAPTER 9



The pipeline, deeper



>> select-object -property *,

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

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

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

>> new-aduser

>>



The syntax might be a bit ugly, but this is an incredibly powerful technique. It’s also

usable in many other places in PowerShell, and you’ll see it again in upcoming chapters. You’ll even see it in the examples contained in PowerShell’s help files: Run Help

Select -Example and look for yourself.



9.6



Parenthetical commands

Sometimes, no matter how hard you try, you can’t make pipeline input work. For

example, consider the Get-WmiObject command. You’ll learn more about it in an

upcoming chapter, but for right now, look at the help for its -ComputerName property,

as shown in figure 9.13.



Figure 9.13



Reading the full help for Get-WmiObject



www.it-ebooks.info



Extracting the value from a single property



111



This parameter doesn’t accept computer names from the pipeline. How can we

retrieve names from someplace—like our text file, which contains one computer

name per line—and feed them to the command? The following won’t work:

PS C:\> get-content .\computers.txt | get-wmiobject -class win32_bios



The String objects produced by Get-Content won’t match the -computerName

parameter of Get-WmiObject. What can we do? Use parentheses:

PS C:\> Get-WmiObject -class Win32_BIOS -ComputerName (Get-Content .\comput

ers.txt)



Think back to high school algebra class, and you’ll recall that parentheses mean “do

this first.” That’s what PowerShell does: it runs the parenthetical command first.

The results of that command—in this case, a bunch of String objects—are fed to the

parameter. Because -ComputerName happens to want a bunch of String objects, the

command works.

If you have a couple of computers with which you can test this,

go ahead and try that command. Put the correct computer names or IP

addresses into your own Computers.txt file. This will work best for computers

all in the same domain, because permissions will be taken care of more easily

in that environment.

TRY IT NOW



The parenthetical command trick is powerful because it doesn’t rely on pipeline

parameter binding at all—it takes objects and sticks them right into the parameter.

But the technique doesn’t work if your parenthetical command isn’t generating the

exact type of object that the parameter expects, which means sometimes you’ll have to

manipulate things a bit. Let’s look at how.



9.7



Extracting the value from a single property

Earlier in this chapter, we showed you an example of using parentheses to execute

Get-Content, feeding its output to the parameter of another cmdlet:

Get-Service -computerName (Get-Content names.txt)



Rather than getting your computer names from a static text file, you might want to

query them from Active Directory. With the ActiveDirectory module (available on a

Windows Server 2008 R2 or later domain controller, and installable with the Remote

Server Administration Tools, or RSAT), you could query all of your domain controllers:

get-adcomputer -filter * -searchbase "ou=domain controllers,

➥dc=company,dc=pri"



Could you use the same parentheses trick to feed computer names to Get-Service?

For example, would this work?

Get-Service -computerName (Get-ADComputer -filter *

➥-searchBase "ou=domain controllers,dc=company,dc=pri")



www.it-ebooks.info



112



CHAPTER 9



The pipeline, deeper



Above and beyond

If you don’t have a domain controller handy, that’s okay—we’ll quickly tell you what

you need to know about the Get-ADComputer command.

First, it’s contained in a module named ActiveDirectory. As we already mentioned,

that module installs on any Windows Server 2008 R2 or later domain controller, and

it’s available in the RSAT to install on a client computer that belongs to a domain.

Second, the command—as you might expect—retrieves computer objects from the

domain.

Third, it has two useful parameters. -Filter * will retrieve all computers, and you

could specify other filter criteria to limit the results, such as specifying a single computer name. The -SearchBase parameter tells the command where to start looking

for computers; in this example, we’re having it start in the Domain Controllers organizational unit (OU) of the Company.com domain:

get-adcomputer -filter * -searchbase "ou=domain controllers,

➥dc=company,dc=pri"



Fourth, computer objects have a Name property, which contains the computers’ host

name.

We realize that throwing this kind of command at you—which, depending on your lab

environment, you might not have access to—might be a bit unfair. But it’s an incredibly useful command for the scenarios we’re looking at, and it’s one you’d definitely

want to use in a production environment. Provided you can keep the preceding four

facts in mind, you should be fine for this chapter.



Sadly, it won’t. Look at the help for Get-Service, and you’ll see that the -computerName

parameter expects String values.

Run this instead:

get-adcomputer -filter * -searchbase "ou=domain controllers,

➥dc=company,dc=pri" | gm



Get-Member reveals that Get-ADComputer is producing objects of the type ADComputer.

Those aren’t String objects, so -computerName won’t know what to do with them. But

the ADComputer objects do have a Name property. What you need to do is extract the

values of the objects’ Name properties, and feed those values, which are computer

names, to the -ComputerName parameter.



This is an important fact about PowerShell, and if you’re a bit lost right

now, STOP and reread the preceding paragraphs. Get-ADComputer produces

objects of the type ADComputer; Get-Member proves it. The -ComputerName

parameter of Get-Service can’t accept an ADComputer object; it accepts only

String objects, as shown in its help file. Therefore, that parenthetical command won’t work as written.

TIP



www.it-ebooks.info



113



Extracting the value from a single property



Once again, the Select-Object cmdlet can rescue you, because it includes an

-expandProperty parameter, which accepts a property name. It will take that property,

extract its values, and return those values as the output of Select-Object. Consider this

example:

get-adcomputer -filter * -searchbase "ou=domain controllers,

➥dc=company,dc=pri" | Select-Object -expand name



You should get a simple list of computer names. Those can be fed to the -computerName

parameter of Get-Service (or any other cmdlet that has a -computerName parameter):

Get-Service -computerName (get-adcomputer -filter *

➥-searchbase "ou=domain controllers,dc=company,dc=pri" |

➥Select-Object -expand name)



TIP



Once again, this is an important concept. Normally, a command like



Select-Object -Property Name produces objects that happen to only have

a Name property, because that’s all we specified. The -computerName parameter doesn’t want some random object that has a Name property; it wants a

String, which is a much simpler value. -Expand Name goes into the Name



property and extracts its values, resulting in simple strings being returned

from the command.

Again, this is a cool trick that makes it possible to combine an even wider variety of commands with each other, saving you typing and making PowerShell do more of the work.

Now that you’ve seen all that coolness with Get-ADComputer, let’s look at a similar

example using commands you should have access to. We’re assuming you’re running

the latest version of Windows, but for this example you don’t need to be in a domain,

or have access to a domain controller or even to a server OS. We’re going to stick with

the general theme of “getting computer names” because that’s such a common production need.

Start by creating a CSV file in Notepad that looks like the one in figure 9.14. If you

provide computer names that are valid on your network, you’ll be able to run the

example commands. If you only have one computer, use “localhost” as the host name,

and enter it three or four times. It’ll still work.



Figure 9.14 Make sure you can

import your CSV file using

Import-CSV and get results

similar to those shown here.



www.it-ebooks.info



114



CHAPTER 9



The pipeline, deeper



Now let’s say that you want to get a list of running processes from each of these computers. If you examine the help for Get-Process, as shown in figure 9.15, you’ll see that

its -computerName parameter does accept pipeline input ByPropertyName. It expects its

input to be objects of the type String. We’re not going to fuss around with pipeline

input, though; we’re going to focus on property extraction. The relevant information

in the help file is the fact that -ComputerName needs one or more String objects.



Figure 9.15



Verifying the data type needed by the -ComputerName parameter



Back to basics: start by seeing what Command A produces by piping it to Get-Member.

Figure 9.16 shows the results.

Import-CSV’s PSCustomObject output isn’t a String, so the following won’t work:

PS C:\> Get-Process -computerName (import-csv .\computers.csv)



Let’s try selecting the HostName field from the CSV, and see what that produces. You

should see what’s shown in figure 9.17.



www.it-ebooks.info



Extracting the value from a single property



Figure 9.16



Import-CSV produces objects of the type PSCustomObject.



Figure 9.17



Selecting a single property still gives you a PSCustomObject.



www.it-ebooks.info



115



116



CHAPTER 9



The pipeline, deeper



You’ve still got a PSCustomObject, but it has fewer properties than before. That’s

the point about Select-Object and its -Property parameter: it doesn’t change the

fact that you’re outputting an entire object.

The -ComputerName parameter can’t accept a PSCustomObject, so this still won’t

work:

PS C:\> Get-Process -computerName (import-csv .\computers.csv |

select -property hostname)



This is where the -ExpandProperty parameter works. Again, let’s try it on its own and

see what it produces, as shown in figure 9.18.

Because the Hostname property contained text strings, -ExpandProperty was able

to expand those values into plain String objects, which is what -ComputerName wants.

This means the following will work:

PS C:\> Get-Process -computerName (import-csv .\computers.csv |

select -expand hostname)



Figure 9.18



You finally have a String object as output!



www.it-ebooks.info



Lab



117



This is a powerful technique. It can be a little hard to grasp at first, but understanding

that a property is kind of like a box can help. With Select -Property, you’re deciding

what boxes you want, but you’ve still got boxes. With Select -ExpandProperty,

you’re extracting the contents of the box, and getting rid of the box entirely. You’re

left with the contents.



9.8



Lab

NOTE



For this lab, you’ll need any computer running PowerShell v3.



Once again, we’ve covered a lot of important concepts in a short amount of time. The

best way to cement your new knowledge is to put it to immediate use. We recommend

doing the following tasks in order, because they build on each other to help remind

you what you’ve learned and to help you find practical ways to use that knowledge.

To make this a bit trickier, we’re going to force you to consider the

Get-ADComputer command. Any Windows Server 2008 R2 or later domain controller

has this command installed, but you don’t need one. You only need to know three

things:

 The



Get-ADComputer command has a -filter parameter; running

Get-ADComputer -filter * will retrieve all computer objects in the domain.

 Domain computer objects have a Name property that contains the computer’s



host name.

 Domain computer objects have the TypeName



ADComputer, which means

Get-ADComputer produces objects of the type ADComputer.



That’s all you should need to know. With that in mind, complete these tasks:

NOTE You’re not being asked to run these commands. Instead, you’re being

asked if these commands will function or not, and why. You’ve been told how

Get-ADComputer works, and what it produces; you can read the help to discover what other commands expect and accept.

1



Would the following command work to retrieve a list of installed hotfixes from

all computers in the specified domain? Why or why not? Write out an explanation, similar to the ones we provided earlier in this chapter.

Get-Hotfix -computerName (get-adcomputer -filter * |

Select-Object -expand name)



2



Would this alternative command work to retrieve the list of hotfixes from the

same computers? Why or why not? Write out an explanation, similar to the ones

we provided earlier in this chapter.

get-adcomputer -filter * |

Get-HotFix



3



Would this third version of the command work to retrieve the list of hotfixes

from the domain computers? Why or why not? Write out an explanation, similar to the ones we provided earlier in this chapter.



www.it-ebooks.info



118



CHAPTER 9



The pipeline, deeper



get-adcomputer -filter * |

Select-Object @{l='computername';e={$_.name}} |

Get-Hotfix

4



5



6



Write a command that uses pipeline parameter binding to retrieve a list of running processes from every computer in an Active Directory (AD) domain. Don’t

use parentheses.

Write a command that retrieves a list of installed services from every computer

in an AD domain. Don’t use pipeline input; instead use a parenthetical command (a command in parentheses).

Sometimes Microsoft forgets to add a pipeline parameter binding to a cmdlet.

For example, would the following command work to retrieve information from

every computer in the domain? Write out an explanation, similar to the ones we

provided earlier in this chapter.

get-adcomputer -filter * |

Select-Object @{l='computername';e={$_.name}} |

Get-WmiObject -class Win32_BIOS



9.9



Further exploration

We find that many students have difficulty embracing this pipeline input concept,

mainly because it’s so abstract. If you find yourself in that situation, head to MoreLunches.com. Find this book’s cover image or name, and click on it. Scroll to the

Downloads section, and download the Pipeline Input Workbook. Print as many copies as you like, grab a pencil, and start using it to walk through examples like

Get-Service | Stop-Service. The workbook provides step-by-step instructions for

working through the entire pipeline input process.



www.it-ebooks.info



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

×