With all of this,
it's time to go back into PowerShell so I can show you
how to work with objects one at a time.
Hopefully you can take advantage of the PowerShell pipeline and manage at scale,
but when you can't, you'll have to do things like this.
Alright,
I'm going to assume that you're going to read the help for foreach‑object.
Let me just get in and demo it.
Let me begin with at least showing you the demo from the slide,
just so you can see this in action.
So 1..10, remember that dot dot is the range operator,
foreach‑object that comes through the pipeline,
I'm going to multiply that object, in this case the numbers 1 through 10,
by 2, and PowerShell then writes that object to the pipeline.
And just to show you that this is still going on,
this is still PowerShell pipeline stuff,
let's rerun this command, and I'm going to pipe this now to measure‑object.
I don't have to specify a property here,
because the number itself, the object, that is the property,
that is the value.
So if PowerShell does not see a property for measure‑object,
it just assumes that you must be piping in a number,
something that measure‑object can work with.
And so the AllStats will go through, and I can get the count,
and again, the average, the sum,
all the other statistics that measure‑object will provide.
Let's do one other here.
Let's do one more example,
and this is kind of to reinforce something we
looked at in the last demonstration.
So I'm going to do the foreach, and let's measure the object,
get all those statistics, but, you know,
I don't want to see the Property property,
that's blank, just show me the ones that have the numbers there.
So it's much nicer, cleaner output,
we kind of saw that in a previous demonstration.
Let me also show you one other example here,
because you will see this out in the wild,
out, people post this and use this all the time.
That percent symbol that you see there is the alias for foreach‑object.
Personally, I'm not a big fan of that, because if you see that,
as you see that here, and you're new to PowerShell,
you have no idea what that means.
It's cryptic.
You have to go look up, okay, what does percent symbol indicate,
whereas if you see foreach‑object, that's at least a little clearer.
But the result is still the same,
for each number that comes through the pipeline,
divide it by 2, and there you can see the results.
When you're working with PowerShell interactively in the console,
if you want to use the percent symbol, go right ahead.
It's just as easy to start typing foreach and hit Tab
and let PowerShell Tab complete it.
Now let's look at this with real objects other than just number.
And, again, to reinforce the concepts,
we'll start with my generic Get‑Vegetable command.
So we do Get‑Vegetable, and I'm going to look at get‑member here,
because there is a method here called Peel.
The Peel method has no parameters.
That's why you see just the parentheses with nothing inside.
If I look at my output for this cmdlet and look at the objects,
there is a property that indicates whether something is peeled or not.
So right now you can see nothing is peeled.
There are no commands that will allow me to peel or to invoke that method,
so if I want to use that method, I have to do it individually.
So I'll just grab, say, the Carrot vegetables.
For each Carrot object that comes through the pipeline,
I'm going to invoke the peel method.
So $_ is the current object, and then .peel,
and then in parentheses,
you have to include the parentheses for the method even
if it doesn't have any parameters.
Now, that method doesn't write anything to the pipeline,
so I don't see a result, but we can easily verify that.
Let's just get all the C vegetables, and again,
just select a few properties like the Name and IsPeeled.
So there we go, so Carrot, you can see there actually IsPeeled,
so I know that that method did its thing.
If I wanted to use that method again, I had to invoke it or use it one at a time.
Let's look at another example here.
I'm going to change to my work folder here,
and I'm going to create two test files, and let's do test.txt,
and then I'm just going to, again, create text2.txt.
All I'm doing is running get‑date and sending the output instead
of to the pipeline and showing on my screen,
I'm sending it to the text file.
Now if I look at my files here, and select the name and attributes properties,
you can see the results there.
Now,
I happen to know that if I look at a particular file
like test.txt and look at get‑member, that there is a method called Encrypt.
So I want to encrypt each of the files, or not all the files,
I want to encrypt my test files that I just created.
There's no cmdlet out of the box that will do that for me.
I can use that method, but again,
I have to invoke it or run it for each object that comes through the pipeline.
So let's do a listing of my test.txt files.
For each object, I'm going to invoke or run that encrypt method,
and again, it's all done.
The method doesn't write anything to the pipelines, so I don't see a result.
But I can verify the results,
let's rerun the directory listing and select the name and attributes,
and now you can see that those files actually are encrypted,
so that did work.
Sometimes you want to take advantage of the foreach,
because there is no other way to do something using the PowerShell pipeline.
Now what I'm about to show you is not necessarily the
only way to accomplish this task, but it's a good illustration,
I think, of the concepts here.
So if you look at help, for Get‑Volume, there is a parameter called cimsession,
which, in essence, is a remote computer name.
Don't worry too much about cimsessions and remoting,
because you may not have gotten into that yet.
If I give a computer name a value to cimsession,
it will connect to that computer and get me the volume information.
I have a text file in my scripts folder called servers.txt,
and you can see the servers that are listed there.
I'd like to be able to pipe this list to Get‑Volume and get the
C drive information for all those servers,
so I might try something like this, get‑content and then pipe it to Get‑Volume.
And that fails, and the error message tells you that it fails.
Scroll back up here.
If you looked at the help output,
you can see that this parameter does not accept pipeline input,
so in order to give it a value, I'm going to have to do it one at a time.
Technically,
I could do multiple values at the same time because see that
cimsession and the little double square brackets,
I could do Get‑Volume ‑cimsession server 1,
server 2, server 3, all separated by commas,
but, you know,
I want to take advantage of the pipeline. So I can do something like this.
So let's get my list of servers and the whole
expression I'm going to save to a variable,
$c.
For each server name that comes through that list,
I'm going to assign it the value to cimsession,
to that parameter, and we're going to get Drive C.
PowerShell will run for a moment and saves the results to $c.
Pretty cool, so that worked, I was able to tell PowerShell,
get the list of computers one at a time,
call Get‑Volume and pass that computer name and feed
that into the cimsession parameter.
But, you know, here,
let's continue our little exploration here with
these cmdlets to work with objects.
Let's take that variable and let's pipe to Select object,
and let me select a few properties.
Now I know from piping this to get‑member, I know what the property names are.
So I want to see the computer name because I can't tell that
from the output that I see there from $c,
the DriveLetter and any parameter that starts with Size,
and once again, I'm using the wild card there.
Cool, that's a much easier output.
Now I can see the Size and SizeRemaining of each of
the servers that were in my list.
Eventually you'll learn some other tricks to format those numbers into
megabytes or gigabytes or something a little more useful to you,
but for now, PowerShell selected what I needed and presented it on the screen.
How about a more complete example of all of this?
Let's try a directory listing of windows and get all the
files in it, and let's send this to group object and group
on the extension property.
Then we'll select some properties, we'll do the Name,
Count, and now I'm going to do something slightly advanced.
You'll see examples of this in the help for select object.
I'm going to create a custom property on the fly,
don't worry too much if you don't fully understand it at this point.
I'm going to create a property called Size,
and the value of Size is going to be the results of this
Expression script block that I'm doing.
And I'm going to take the group object, remember,
$_ means the current object in the pipeline.
So I have a group object that I'm processing.
Remember,
the group property is a list of all of the related files,
in this case, grouped by extension.
So I'm going to take all of those files and pipe them to Measure
object and measure the length and get the sum.
Now all I want is just that sum value,
so one way to do that is to pipe this to select object and tell
it to use expandproperty on that sum property.
That'll just give me the value,
it won't give me an object with a single property of sum.
That value then gets assigned to the Size property that I'm creating on the fly.
So I got a new object going through the pipeline.
I can sort on that new property that I created in descending
order and then Select just the first 5.
So now I can see in my windows folder these are the file extensions that are
using the most space or have the the largest number of files,
and, not surprisingly,
the executable files in C windows are taking up the most space.
There are some alternate ways of using foreach‑object,
which I at least need to show you,
even though I don't necessarily recommend using them,
and I don't use them really myself, but let me show you.
So let's go to my scripts folder, and I'm just going to create,
this is a good example of using that range operator,
and I'm going to create test files.
So for each number that comes in,
I'm going to take Get‑Date and pipe it to Out‑File and create a
file called secret‑ whatever the number is,
secret‑12345.dat.
The contents would just be the date.
And if I take a look at the list, so I just created those files.
Now if I wanted to modify, say I want to hide those files,
I need to adjust and modify the attributes property of those files.
One way to do it is like this.
I can get my directory listing of those files,
pipe them to foreach, instead of using $_,
technically you're allowed to use something called
psitem. $psitem is the same thing as $_,
it means the current object in the pipeline,
and I'm just telling it add Hidden to the attributes property.
The += sign is a special operator that says add it to an existing collection.
Now that they're hidden,
if I want to see them actually I have to use the ‑force parameter,
and in the output there you can see that they are in fact hidden.
I'm not a big fan of $psitem.
For one, not a lot of people have used it,
and I think it's just kind of a little more confusing,
personally, myself.
I think you should be able to do $_, so in other words, do this.
So I get all my files again that are hidden,
and in this case I'm going to undo the operation using
$_ and remove that Hidden attributes, and now I've unhidden those files.
I think that's a much cleaner approach, it's more consistent, but pick one.
If you happen to like $psitem, then use that all the time.
The worst thing to do, though,
is to go back and forth and have some code using $_ and some
using $psitem. Pick one and go with that.
And there you can see that the files are in fact now unhidden.
One thing I want to point out, though, with foreach‑object,
do not, I mean it'll work, because I'm going to show you here that it will work,
don't do this.
Don't say, hey, I want to get a list of the files,
but for each one, just show me the name property.
Don't do that.
This is what we used to do with VBScript and with
other kind of old legacy‑style tools.
This is where you're thinking like text.
You're saying, give me this thing, but just show me the text.
You don't have to do that one at a time, even though, yes, I know it works.
When I see something like this, or if you see something like this,
that should be your clue, okay, this person does not fully,
they haven't gotten their head around this objects‑in‑the‑pipeline paradigm.
The PowerShell way to do it would be this.
If all I want to see is the file name, then just tell PowerShell,
get me these file objects, and then just select the name.
In this particular case, what, remember, our PowerShell is doing,
it's creating a custom object, in this case with a single property called Name.
If you truly just want the values, say, for a text list,
you can tell PowerShell to expand that property,
so we'll just select object, expand that Name property.
Now I don't have that little name header,
that's my clue that this is not an object,
it's just a list of names.
And, in fact, once you get more proficient in PowerShell,
you can even shortcut all of that and just use syntax like this,
gives me the same results.
So the command inside the parentheses runs first,
and then I can use the .name property and get the name
property of all of those objects.
So implicitly PowerShell is kind of doing a foreach object,
don't worry, you don't have to get that way right now, but I wanted to point that out to you.