PowerShell Tutorials
PowerShell Tutorials
The initial lessons are concentrated around PowerShell as a Command Shell. The
commands and syntaxes you learn will be utilized in script writing. An enormous feature
of PowerShell is the ability to build and test code at the command prompt. If you have
experience in VBScript you understand. VBScript doesn¶t have a command line, you
write the script, test it, and make adjustments. With PowerShell you can test
functionality within the command line before writing it to your script, very powerful!
2
c
c
c
PowerShell is required for tutorials on this site. If PowerShell is not installed on the
system, please do so before moving on. A page on this site has been provided to
assist in installing PowerShell. It can be found at Categories -> PowerShell Downloads -
> Download PowerShell 1.0.
c
PowerShell is a new« ok how many times have you read that already? PowerShell
is a new command shell from Microsoft and yes it is a command prompt and scripting
environment, it can even be both at the same time. But what does PowerShell really
mean for a systems administrator? What are the benefits in learning PowerShell? If you
manage resources with VBScript you already know the answers. Active Directory
domains are becoming larger and more complex. For those administrators that are still
chained to GUI tools and the Microsoft Management Console, PowerShell will set you
free!!!
It has become a daunting task to manage resources in large domains, GUI just won't
DUI anymore. For example, take the recent DST (Daylight Savings Time) change.
Microsoft was slow to respond (in my opinion) but did supply hot fixes for XP and
Windows 2003. Windows 2000 was a different story, system admins had to rely on a
manual edit using tzedit.exe (unless you had a premier contract). Am I bringing back
any nightmares? Here was my nightmare; the boss asked, "How do we know that the
DST hot fixes and the manual tzedit actually worked?" Gulp! Thank god I was already
working on the answer to that question. I found a KB Article posted on the Microsoft
web site listing the new DST registry entries and their locations. So with VBScript I
enumerated the registry settings, based on operating system version, and created a
report. I found a 25% failure rate after applying hot fixes and tzedit. So, I wrote another
script that would edit the registry settings with the proper configuration. Thankfully, all of
my Server Systems (300+) sprung ahead to the proper DST settings. Ok, so now you
are thinking "why are we talking about VBScript? This is a PowerShell tutorial!!!" My
point is, I know a lot of IT workers that had to manually update the registry when the
clocks didn't roll forward, message boards and forums were full of postings. What would
you rather do, logon to each server and manually fix the problem or run a script to fix
the issue for you? PowerShell would have been a great tool for this situation; I was
just more familiar with VBScript at the time.
I've read and been asked the following, "VBScript is still a viable tool« so why should I
learn PowerShell?" I have a couple of simple answers for that:
1. PowerShell was designed for .NET objects; VBScript does not support a
method for communicating or interacting with .NET. 2e will talk more
about .NET in later tutorials.
2. Learning PowerShell will further advance your career. Trust me, it will.
This Introduction was not based on what PowerShell is but what PowerShell, as a Shell
and a Scripting Language, can do for you. The DST example is only the tip of the
iceberg when is comes to the power of scripting languages. What PowerShell "is" you
will discover as you continue learning. What's great about PowerShell, you will be able
to use it right out of the gate to complete simple tasks. As your knowledge grows you
will be able to take on more complex tasks.
c
PowerShell is object-based not text-based
This concept will take a little time grasp for dos/cmd.exe and batch script writers. Those
using VBScript and other programming languages already understand the concept. The
basic difference, traditional command prompt output is text-based while output in
PowerShell is not. It looks like text but it is actually an object. Why is this powerful?
Because the output of a PowerShell command (the object) can be piped into another
command without additional programming. With traditional scripting, if you wanted to
use the output of one command in another, additional programming would be required
to manipulate the data in a format the second command could understand. What is an
object? This should sound familiar to the Windows Administrators out there«
"Everything in an Active Directory Domain is an object." Servers, Computers, Printers,
Shares, Organizational Units, Security Groups, Group Policy Objects, Users, etc« With
PowerShell we can interact with these objects to enumerate information (object-
properties) and/or create, modify, or delete objects and/or object-properties (object-
methods).
PowerShell Commands are customizable
PowerShell commands are referred to as Cmdlets. With the installation of PowerShell
there are over a hundred cmdlets for you to get up close and personal with. The
PowerShell team, in their infinite wisdom, created aliases to allow us to use the
traditional commands we have become accustomed to (dir, cd, del, copy, etc«). Even
the UNIX guys get a break with provided aliases (ls, man, etc«). PowerShell allows you
to create your own aliases as well as creating your own cmdlets. Yep, unlike dos/cmd
and reskit exe's, PowerShell provides a method to create your own PowerShell cmdlets.
PowerShell is a Command line interpreter and a scripting environment
In a nutshell you have the best of both worlds within PowerShell. DOS was a command
line interpreter, enter command get output. Sure you could use batch files, but in reality
a batch file just entered the commands for you. VBScript utilizes WSH (Windows
Scripting Host); you can't enter VBScript code in a command prompt. With PowerShell
not only can you enter commands, you can build script-blocks from the PowerShell
command line. You will be doing this in later tutorials.
2 c
Let's take a look at the Windows PowerShell Console. Go to Start -> Programs ->
Windows PowerShell 1.0 -> Windows PowerShell
You can also launch PowerShell from a command prompt or in start -> run by simply
typing powershell
Feel free to choose the directory path of your choice. If your path has a space in it, don't
forget to double-quote it. Example: "C:\Program Files\MyScripts." I will be working from
the C:\MyScripts directory path throughout the tutorials.
Exercise 2: Customizing color and text-size
Remember the DOS prompt with the blue background and yellow text? Ok, I'm dating
myself but at least I didn't say monochrome. I'm going to change the shortcut to those
colors.
Next I'm going to make the text larger so I don't have to squint.
Do you see the following? I mean can you really see it now?
Take a few minutes and play around with all the options in the shortcut's properties.
Customize the shell to your preference. If you want to go back to the default text-size it
is 8 x 12. You can also get to properties by clicking on the PowerShell icon in the upper
left-hand corner. Just be aware that when you click "OK" you will be prompted to
change the settings of the current window or to modify the shortcut.
Exercise 3: Editing Features in the PowerShell Console
In the last exercise of this tutorial I want to introduce some editing features. I'm just
going to list them and ask that you play around in the console until you are comfortable
with how they work.
First, enter the following commands at the command prompt (for this exercise, what the
code does is not important):
get-acl <enter>
get-alias <enter>
get-command <enter>
get-date <enter>
Locate and type the keys below on the keyboard, watch what happens.
2
c
c
c
?
The concepts in this tutorial have come from my readings of Bruce Payette's book -
2indows PowerShell in Action. Bruce is a founding member of the PowerShell team
and is a co-designer of the PowerShell language. His book is highly recommended and
has been made available from this site. Who better to learn about PowerShell than from
the designer himself!
There are four categories of PowerShell commands: Cmdlet (Command-Let),
PowerShell Functions, PowerShell Scripts, and native Windows commands. Each
category will be examined in tutorials on this site. Lesson 2 focuses on the PowerShell
cmdlet, so let's get started«
There are over a hundred new PowerShell commands to learn, but no need to panic.
Unlike most other command-line interfaces, PowerShell commands have been
standardized using a "verb-noun" naming convention know as a cmdlet. This standard
simplifies the learning curve and provides a better description of what the cmdlet does.
To see a list of cmdlets available in PowerShell type the following cmdlet:
get-command <enter>
ëote: <enter> denotes typing the Enter/Return key on your keyboard.
R
The "Name" column lists the cmdlets in the "verb-noun" naming convention.
Next, let's list all the commands that use a specific verb. The following command yields
all cmdlets that use the verb "Get."
get-command -Verb Get <enter>
R
Play around with the -Verb parameter, try finding commands that use the verbs; Add,
Clear, New, and Set.
Getting commands that use specific nouns is just as easy. Type the following command
to see which cmdlets use the noun "Service."
get-command -Noun Service <enter>
R
Just as it sounds, the verb describes an action and the noun describes the "what" to
take the action against. One thing I want to mention before moving forward, the
PowerShell command line is not case-sensitive. In PowerShell - "get-service" or "Get-
Service" or even "GeT-SerVIce" is the same command.
r
In learning new technologies, it is important to find information quickly and easily. Get-
Help cmdlet has been designed for that purpose; this will be the most utilized cmdlet
until you become more proficient.
ret-Help Examples:
Information about Get-Help cmdlet. Includes description, syntax, and remarks.
Get-Help
R
You should now have a list of services on the computer as well as their status, similar to
the list above. Which GUI tool gives us the same information? The Services MMC
(Microsoft Management Console). Launch the Services MMC from Start -> Programs ->
Administrative Tools -> Services. If Administrative Tools are hidden from the Programs
Menu, you can launch it by typing services.msc from the PowerShell command-line. As
stated earlier, one of the PowerShell command categories is "native windows
commands." This is how we are able to launch services.msc from the PowerShell
command-line.
R
R
ëote: When you run the Stop-Service cmdlet there is no indication that the
service has actually stopped. This is why I ran the ret-Service command to verify
the status changed to "Stopped."
We should see the same change in the Services.msc GUI. In the GUI a Status of
"Blank" means "Stopped."
R
The following syntax will start a service: Start-Service [-name] or Start-Service [-
displayëame]. Look familiar? Again, let's check the status, start the service, and verify
the status has changed.
Get-Service -name Browser <enter>
Start-Service -name Browser <enter>
Get-Service -name Browser <enter>
R
Check the GUI, the status of Browser should be "Started" (make sure to refresh the
view).
This exercise should give you an indication of the benefits of using PowerShell. With
just a couple of cmdlets we were able to stop and start a service. Traditionally, an
Administrator would launch the GUI, select the service, and then either stop or start it.
Doesn't seem like a big deal until you are asked to stop a service on multiple
computers. Through PowerShell Scripting you will be able to start, stop, and change
status types of a service on multiple computers without much effort. Write a script, run-
it, and then kick you feet up on the desk.
This tutorial has introduced the PowerShell naming convention, cmdlets, getting help,
and an example of using the Service cmdlet. As stated before, there are over a hundred
cmdlets in PowerShell. This should be enough to keep you busy for awhile. See you in
the next tutorial where we will be covering PowerShell Aliases.
2
c
c
c
Aliasing in PowerShell allows for the use of commands we become accustomed to.
Windows users can utilize commands like dir, move, type, cls, etc« PowerShell also
provides a set of aliases for Linux; ls, pwd, mv, man, cat, etc« PowerShell Aliases are
provided for the purpose of allowing new users the ability to quickly interact with the
shell. An alias is an alternative name assigned to a cmdlet. For example, ³dir´ is an alias
for ³Get-ChildItem.´ This tutorial presents two types of aliases:
R
While browsing through the list, notice that there are multiple Aliases for the ³Get-
ChildItem´ cmdlet. Windows ³dir´ command, Unix ³ls´ command, and a PowerShell alias
³gci´ command. No matter which alias you have chosen to use, typing any one of the
aliases will result in the running of the ³Get-ChildItem´ cmdlet. Let¶s test this out, type
the following:
dir <enter>
ls <enter>
gci <enter>
Get-ChildItem <enter>
R
Listed in Image 3.2, we can verify that each command resulted in the same output. In
essence, we just ran ³Get-ChildItem´ four times. There is really not much more to built-
in aliases. They exist to assist you while working in the shell, until you become more
familiar with the cmdlets. User-Defined aliases require a little more attention.
c
Set-Alias Simple syntax, not much to it. Let¶s say I want to create a
User-Defined alias for the ³Get-Service´ cmdlet:
Set-Alias gs Get-Service <enter>
Test your new Alias:
gs <enter>
R
That was easy, so why does a user-defined alias need a little more attention? User-
defined aliases only last while the PowerShell session is active. As soon a you quit the
session, your alias is gone forever. Close your PowerShell session and re-launch
PowerShell. Attempt to use the ³gs´ alias, you will receive the following error:
!"! !
#$ $%O.k. - Recognize the term by creating the alias again:
Set-Alias gs Get-Service
So, we have created a User-defined PowerShell alias and don¶t want to lose it when we
quit the session, what do we do? There are two options to explore:
c
The purpose of Importing and Exporting is to make user-defined aliases available to
multiple machines. Say you wrote a script that uses custom aliases. If you attempted to
run your script on another machine, it would fail. The remote PowerShell session is not
aware of the custom aliases you have created. Unless, you export the aliases to a text
file in which the remote computer could import.
Go ahead and export the ³gs´ alias using the ³Export-Alias´ cmdlet:
Export-Alias -Path Aliases.txt <enter>
Since I am running from my home directory ³C:\MyScripts´ the Aliases.txt file will be
created there. Use the ³-Path´ parameter to set the desired location. ne option is to
save the export file to a UN path so that it is available from a network share. Open
³Aliases.txt´ in notepad:
PS C:\MyScripts>notepad Aliases.txt <enter>
That looks ugly« but, if the alias does not exist, it will get imported. There is actually a
better way to do this. The example above was shown to make you aware of a potential
problem when you are importing and exporting aliases. By using the -Name parameter,
you can export only the aliases you choose. So with our ³gs´ alias let¶s attempt the
following:
Export-Alias -Path Alias.txt -Name gs <enter>
notepad Alias.txt <enter>
R
That looks much better« What do you think would happen if you attempted to import
this file? If your PowerShell Session is still active, you should get the import error
because the ³gs´ alias still exists in the current session. Exit your PowerShell session
and re-launch PowerShell.
Let¶s import the Alias.txt file:
Import-Alias -Path Alias.txt <enter>
gs <enter>
R
No error reported when importing the Alias.txt file and entering the ³gs´ alias provides us
with the output expected.
Importing and Exporting allows for the use of user-defined aliases on local and multiple
systems. What if you just wanted to use custom aliases on your local system and don¶t
want to be burdened with importing a file each time you launch PowerShell? PowerShell
profiles allow you to customize the PowerShell environment at launch time. The last
section of this tutorial introduces the PowerShell profile. We are only going to discuss
profiles as it pertains to user-defined aliases. With Profiles, there are many options to
customize your PowerShell environment, which will be covered in this series.
c c
What is a PowerShell Profile? In simplest terms, a profile is a script that runs at session
startup. The location of the Profile is stored in the $Profile variable, which by default is
³My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1Ǝ
To verify the location of your profile type:
$Profile <enter>
R
In image 3.8 you can see the path to my profile, which happens to be were ³My
Documents´ are stored. As already mentioned, the profile is a script which is denoted by
the ³.ps1Ǝ extension. All PowerShell scripts are identified by this extension. Since the
profile is a PowerShell script we will need to edit it. You can use any PowerShell editor,
in this tutorial I will be using Notepad. Before editing the file we need to check the
PowerShell execution policy.
When PowerShell is first installed the default execution policy is ³Restricted.´ This
means PowerShell will not run scripts or configuration files. Here is a list of policy
levels:
Now that the policy is set to run scripts, let¶s create a profile by following the steps
below:
Step 1. Verify existence of a profile.
test-path $Profile <enter>
If the result = False. No profile exists (continue to step2).
If the result = True. Profile exists (skip steps 2 & 3). Unless you want to create a new
profile, which will delete the current profile.
Step 2. Create a new profile.
New-Item -Path $Profile -ItemType file -Force <enter>
Step 3. Verify new profile was created.
Repeat step 1. Result should equal ³True.´
Let¶s open our new profile in notepad:
notepad $Profile <enter>
R &
Isn¶t that great! We have a blank page! The important thing to note: We have a script file
called ³Microsoft.PowerShell_profile.ps1Ǝ
This script file will be called using the $Profile variable each time a PowerShell session
is launched. What goes into the script file will be up to you, how you decide to configure
your PowerShell environment. For now, let¶s have our profile load our custom user-
defined PowerShell alias. Edit and Save the profile as shown below:
R '
After you have saved the profile, close notepad, and exit the PowerShell session.
Launch a new PowerShell session and verify that your custom alias is functional:
gs <enter>
Viola! your profile has loaded successfully and your alias is working. Use ³Get-Alias´
cmdlet to verify the existence of your new alias:
Get-Alias <enter>
-or- a more refined search:
Get-Alias -Name gs <enter>
c c
c
!
"
Welcome back! Continuing with your PowerShell Training, the goal of this tutorial is to
introduce PowerShell parameters, objects, and formatting output. I¶m excited about this
tutorial as we begin to define and discover the power of working with objects in
PowerShell. By the end of this PowerShell training session you should have a good
understanding of what an object is, how we gather information, and how changes are
made in the environment.
Launch PowerShell and let¶s get started«
c
As mentioned before, the standardization of the PowerShell syntax has reduced the
learning curve. Cmdlets follow a standard ³Verb-Noun´ naming convention and also use
common parameters. ëote: not all cmdlets use these parameters. However, because
the PowerShell engine interprets the parameter (not the cmdlet), each common
parameter is enacted in the same fashion. Below is a list of the Common Parameters:
ëote: Suspend? This option is very useful. Let¶s say you are not sure you want to
execute the cmdlet because you are not sure what the ³ExecutionPolicy´ is set to. You
can verify the ³ExecutionPolicy´ before committing the change:
Set-ExecutionPolicy Unrestricted -confirm<enter>
Are you sure you want«
S<enter> (places the prompt in suspend mode as denoted by ³>>´).
>>Get-ExecutionPolicy<enter>
]esricted (or whatever the policy is set to).
>>exit<enter> (Typing ³exit´ leaves suspend mode and returns to the original command)
Are you sure you want«
Y<enter> (onfirms ³Yes´ and sets the ExecutionPolicy to ³Unrestricted´).
We¶ve covered a few examples of what you can do with parameters. Since you know
how to ³Get-Help´ for a cmdlet, it¶s easy to discover which parameters are available to
any cmdlet. Do some exploring and experimentation before moving on to the ³Objects´
section.
As discussed in an earlier PowerShell tutorial, PowerShell is object-based not text-
based. Since we are working with objects, more information exists than what¶s
presented (by default) on the command line. That information may not be initially visible;
by using PowerShell cmdlets, parameters, and script blocks we can interact with an
object to provide us with the information we require.
What is an Object?
An ³Object´ is something we can gather information from and/or perform an action upon.
An object, in PowerShell, consists of properties (information we can gather) and
methods (actions we can perform).
I don¶t remember where I herd the following explanation but it¶s one that sticks with me.
As an example, let¶s look at a ³light bulb.´ The object should be obvious, it¶s a light bulb.
The properties of a light bulb could be color, wattage, and type (florescent,
incandescent, or halogen). Methods are the actions we can perform on the object such
as; turn on the light bulb and turn off the light bulb. Pretty simple right! Let¶s look at an
object¶s properties and methods.
Ingrain this cmdlet in you head, you will use it constantly: ³ret-Member.´ This cmdlet is
used to examine what properties and methods are available to an object.
Example 1. Properties and Methods of the ³ret-Service´ cmdlet.
Type the following to view the properties and methods of the ³Get-Service´ cmdlet. In
this example, the output of ³Get-Service´ (object) is piped into the ³Get-Member´ cmdlet.
Get-Service | Get-Member<enter>
Get-Member Results
R
You should see something similar to Image 4.1. We have identified which properties
and methods are available in the ³Get-Service´ cmdlet. At this point in your PowerShell
training if you are not familiar with what¶s in the definition column, you are looking at
³Data Types.´ For example, the ³CanStop´ property returns a Boolen ³Type.´ My guess
is that the value would either be ³True´ or ³False.´ Don¶t be concerned with this right
now, we will be covering ³Types´ in another PowerShell tutorial. Just make a mental
note that the ³Get-Member´ cmdlet also returns ³data types.´
Example 2. retting Properties of the ³ret-Service´ cmdlet.
In this example we refine our search to display only properties by using the -
MemberType parameter.
Get-Service | Get-Member -MemberType Property<enter>
Example 3. retting Methods of the ³ret-Service´ cmdlet.
Get-Service | Get-Member -MemberType Method<enter>
For a systems administrator, objects are the ³Holy Grail´ in managing your environment.
Why? Because everything in Windows PowerShell is an object. Let me go off the page
here for a second to explain. Since we connect to objects and gather information
(properties), we are able to compile a report from practically any request our boss
throws at us. If the boss requests that a change (method) is made, we are able to make
those changes to one or more objects in the environment.
Here¶s an example: Overnight, someone has placed a large number of files on the file
server that has taken up 50% of the remaining free space. I know, unrealistic right?!?
Just follow me on this one. The boss wants a report of all files that were created in the
last day. Your answer« ³No Problem.´
Get-ChildItem -Path C:\ -Recurse | Where-Object {$_.LastWriteTime -gt
³08/25/2007Ǝ}<enter>
Let¶s dissect what the command is doing:
What I would like you to notice, what is ³LastWriteTime´? Type the following
command:
Get-ChildItem | Get-Member<enter>
Do you see a property called ³LastWriteTime´? We told the command to find each
object with the ³LastWriteTime´ property that has a value greater than 08/25/2007. ³-gt´
is an operator that means greater than, we talk more about operators in a later tutorial. I
mentioned ³Types´ before as well, the Definition column states that the ³LastWriteTime´
property is a ³System.DateTime´ Type. This means it returns values of this type, which
is why we used the ³DateTime´ type ³08/25/2007.´ Again, we will discuss ³Types´ in a
later PowerShell tutorial.
Did the method ³Turn light bulb On´ work? I¶m hoping that this discussion on objects is
starting to paint the big picture for you. Can you think of what type of properties and
methods are associated with user objects in Active Directory? If the boss asks for a
report of all disabled users; at this point you should recognize that ³user´ is an object,
more than likely it has a property which returns the status of the account, and a method
to either enable or disable it. How about properties and methods associated with
computers, printers, and security groups. We are going to get into how we can connect
to these objects and enumerate/modify them when we discuss WMI, COM objects, and
.NET. But for now, the boss wants us to format the report we gave him in the earlier
example.
¦
When we execute a cmdlet we are relying on PowerShell to display results. The
³Format-´ cmdlets allow us to choose which format to display results in. To get a list of
formatting options, type the following command:
Get-Command Format-*<enter>
Format-Custom
Format-List
Format-Table
Format-Wide
Format-Table
³Format-Table´ cmdlet displays data in rows and columns, similar to what you would
see in an Excel spreadsheet. By default, PowerShell attempts to format the view, but
doesn¶t always display the best results. For example let¶s format the output of the ³Get-
ChildItem´ cmdlet for the ³C:\Windows´ directory.
Get-ChildItem C:\Windows | Format-Table<enter>
I like the table format, but there seems to be too much white space (spaces) between
the columns for my taste. Fortunately, there is a parameter -AutoSize to assist us with
white space issues.
Get-ChildItem C:\Windows | Format-Table -AutoSize<enter>
O.k. maybe that wasn¶t what you were looking for either. As shown from a previous
example, use the <tab> key to cycle through the available parameters for the ³Format-
table´ cmdlet. Expierment with each available parameters to see how format is
manipulated.
Format-List
³Format-List´ cmdlet displays data in« of course, a list. For example:
Get-ChildItem C:\Windows | Format-List<enter>
By default, we get the following properties: Name, CreationTime, LastWriteTime, and
LastAccessTime. The boss looks at the list and requests the full path to the files. Use
the -Property parameter to list the ³FullName´ property. Reminder: use ³ret-
Member´ cmdlet to list the available properties:
Get-ChildItem C:\Windows | Format-List -Property FullName<enter>
If your boss is like mine, I usually hear something like« ³that¶s great, but now I want the
full path to all files and subdirectories, creation date, and last time a file was modified.´
Your answer« ³No Problem!´ To enumerate multiple properties, just separate each
property with a comma (,) as shown in this example:
Get-ChildItem C:\Windows -Recurse | Format-List -Property
FullName,CreationTime,LastWriteTime<enter>
ëote:You can also use the -Property parameter with the ³Format-Table´ cmdlet to
build tables, with each property as a header.
Format-Wide
³Format-Wide´ cmdlet compresses results of a list, to fit the screen:
Get-ChildItem C: | Format-Wide<enter>
The results are in list format sorted by column, similar to the old ³dir /D´ command. You
can customize the number of columns using the -Column "parameter:
Get-ChildItem C: | Format-Wide -Column 3<enter>
rroup-Object
The ³Group-Object´ cmdlet allows us to format output information based on groups. For
example, there is a property call ³Company´ for the object returned by the ³Get-Process´
cmdlet. Let¶s assign the ³Company´ property to a group:
Get-Process | Group-Object Company<enter>
The output groups the information as follows:
Here is another example of how to use the ³Group-Object´ cmdlet. You want to discover
which Event IDs are present in the system log:
Get-EventLog System | Group-Object eventid<enter>
ëote: The ëame column is the Event ID, even though it¶s not labeled as such. By
default, ³rroup-Object´ places the property you specify in the ³ëame´ column.
Sort-Object
From the example above we are presented with a ³Count´ column. This indicates the
number of occurrences per each Event ID. Just as it sounds, the ³Sort-Object´ cmdlet
provides a mechanism to sort results. In this example, I¶m going to further build on the
command above to sort from most occurrences to least:
Get-EventLog System | Group-Object eventid | Sort-Object Count -descending<enter>
The results are now sorted from most to least number of occurrences. Couple of things
to notice here:
î I sorted on the ³Count´ column. You could also sort by ³Name´ or any
column you choose.
î As shown above you can pipe results from one cmdlet to another and then
another, etc«
Convertto-HTML
I love this cmdlet. It¶s not the best html conversion, sometimes the output looks great,
sometimes not. It¶s just fast and I don¶t have to write any code to convert results, like I
did in VBScript. Let¶s send the results of ³Get-Process´ to html.
Get-Process | ConvertTo-html<enter>
Well, the cmdlet preformed the conversion but I want the result saved to an html file. I¶m
going to use the ³Out-File´ cmdlet to redirect the results into a file. This is similar to
using the redirect symbol ³>´ in the old dos command shell.
Get-Process | ConvertTo-html | out-file ³Processes.html´<enter>
To open the .html file use the ³Invoke-Item´ cmdlet. This is equivalent to clicking on a
file where the file type determines which application is launched.
Invoke-Item Processes.html<enter>
The default browser is launched presenting the results saved in the html file. Like I said,
doesn¶t always look great« But it is fast and the html code can be edited (to look pretty)
if desired.
Export-CSV
This is another formatting cmdlet that you are going to love. It takes results and
converts it to a csv file. In the following examples we are going to Export the processes
and open the file in a spreadsheet. You must have Excel or some other type of
spreadsheet installed on the system.
1. Export results to a .csv file´
Get-Process | Export-CSV Processes.csv<enter>
c c #
c
$2
c c #
PowerShell Providers are .NET programs that allow us to work with data stores as if
they were mounted drives. This simplifies accessing external data outside the
PowerShell environment. For example, we can access the registry as if it were a file
system. This translates to being able to use the same cmdlets as working with files and
folders, which are shown in the table below.
Cmdlet Alias Cmd Commands Descritption
Get-Location gl pwd Current Directory.
Set-Location sl cd, chdir Change current directory.
Copy-Item cpi copy Copy Files.
Remove-Item ri del Removes a File or directory.
Move-Item mi move Move a file.
Rename-Item rni rn Rename a file.
Creates a new empty file or
New-Item ni n/a
folder.
Clear-Item cli n/a Clears the contents of a file.
Set-Item si n/a Set the contents of a file.
Mkdir n/a md Creates a new directory.
Sends contents of a file to the
Get-Content gc type
output stream.
Set-Content sc n/a Set the contents of a file.
Take a look at the ³about file´ for more information:
Get-Content $PSHOME\about_Provider.help.txt<enter>
SHORT DESCRIPTION
Windows PowerShell providers provide access to data and components that
would not otherwise be easily accessible at the command line. The data
is presented in a consistent format that resembles a file system drive.
LONG DESCRIPTION
Windows PowerShell providers are .NET programs that make the data in a
specialized data store available in Windows PowerShell so that you can
easily view and manage it.
The data that a provider exposes appears in a drive, much like a hard drive.
You can use any of the built-in cmdlets that the provider supports to manage
the data in the provider drive, in addition to custom cmdlets that are
designed especially for the data.
The providers can also add ³dynamic parameters´ to the built-in cmdlets.
These are parameters that are available only when using the cmdlet with the
provider data.
A Provider is also called a ³snap-in´ which is a dynamic link library (.dll) built into
PowerShell. A library is code that instructs PowerShell to preform an action when we
execute a command. What this means is that we no longer have to write code, as we
did in VBScript, to connect to the registry. The code is provided for us, simplifying our
efforts. New and Custom Providers can be written, but this goes beyond the scope of
this tutorial. The PowerShell Software Developers Kit provides documents should you
wish to build your own Providers.
c c
Using the ³Get-PSProvider´ cmdlet, we obtain a list of available PowerShell Providers:
Get-PSProvider<enter>
PowerShell Providers
R
'
Here is the list of the PoweShell Providers available:
î Alias
î Environment
î FileSystem
î Function
î Registry
î Variable
î Certificate
PS Drives
R
The ³Name´ column reveals the PSDrives available on the system. We connect to each
Provider using the PSDrive appended with a colon (:). ëote: The example in image 5.1
shows the PSDrives without the (:) so you have to remember to use it when mounting a
PSDrive.
Let¶s use this PowerShell training session to explore each of these providers.
Vc c
We discussed what an Alias ³is´ in PowerShell tutorial 3. The Alias Provider enables
access to all the aliases in PowerShell. To mount a PSDrive we use the ³Set-Location´
cmdlet. In this example, we want to mount the ³Alias:´ PSDrive. Don¶t Forget the
colon(:).
Set-Location Alias:<enter>
Where-Object Filter
R
We have worked a lot with aliases in a previous tutorial, so I¶m going to move along to
the next Provider. Feel free to use the commands listed in the table (above) and
experiment with the Alias Provider.
Vc
c
You may already be familiar with what the Environment Providers is, it is equivalent to
running the ³set´ command in a windows CMD command shell. It provides a listing of all
the environment variable defined on the system. Graphically, you can view the
environment variables by going to System Properties -> Advanced Tab -> Click the
³Environment Variables´ button.
ENV Variables
R
Example 1. List Environment Variables
Get-PSDrive<enter>
Set-Location env:<enter>
Get-ChildItem<enter>
List Variables
R
Example 2. Obtain the value of an Environment Variable
Get-ChildItem OS<enter>
1. Create a new variable using the ³New-Item´ cmdlet. Let¶s call the new
variable ³MyVariable´ and give it a value of ³This is my new variable.´ The
Path argument will be a dot (.) meaning current location, which would be
³env:´
New-Item -Path . -Name MyVariable -Value ³This is my new
variable´<enter>
Create Variable
R
Use ³Get-ChildItem´ cmdlet to verify that the new variable exists.
Example 4. Renaming the Environment Variable
Get-ChildItem<enter>
Remove-Item MyRenVar<enter>
Get-ChildItem<enter>
c ¦ #
c
By default, the File System Provider is accessed when PowerShell is launched. The File
System Provider allows you to create, retrieve, and remove files and folders. Also, the
File System Provider allow you to modify files by either appending or overwritting data.
This section of the PowerShell Providers tutorial explains how to do this.
Example 1. Listing Files and Directories
1. Connect to the File System Provider. Close and re-launch PowerShell -or-
connect to the File System Provider using the ³Set-Location´ cmdlet. Use
the backslash (\) character to connect to the root of C: Drive
Set-Location C:\<enter>
Get-ChildItem<enter>
Get-ChildItem -Recurse<enter>
If your file system is large, the command in step 3 may take awhile. Use ³Ctrl + C´ to
stop processing commands in PowerShell, just like you did in CMD command shell.
What is the ³Mode´ column? 5 bits of information you need to know.
î First entry is either ³d´ (indicates item is a directory) or ³-´ (indicates item is
a file).
î The last 4 entries present the properties of a File and/or Directory (a r h s).
³a´ = archive bit is set, ³r´ = read only, ³h´ = hidden, and ³s´ = system. A ³-´
in any of these entries means the bit is not set.
Mode
R
&
ëote: By default, ³ret-ChildItem´ cmdlet or an Alias does not show hidden files
and Directories. To show hidden files use the ³-force´ parameter.
Get-ChildItem -Force<enter>
As stated earlier in this PowerShell tutorial, Providers allow the use of the same
cmdlets. Here is a second look at the cmdlet table, so that you don¶t have to scroll back
to the top.
Cmdlet Alias Cmd Commands Descritption
Get-Location gl pwd Current Directory.
Set-Location sl cd, chdir Change current directory.
Copy-Item cpi copy Copy Files.
Remove-Item ri del Removes a File or directory.
Move-Item mi move Move a file.
Rename-Item rni rn Rename a file.
Creates a new empty file or
New-Item ni n/a
folder.
Clear-Item cli n/a Clears the contents of a file.
Set-Item si n/a Set the contents of a file.
Mkdir n/a md Creates a new directory.
Sends contents of a file to the
Get-Content gc type
output stream.
Set-Content sc n/a Set the contents of a file.
Example 2. Using ³ret-Location´ Cmdlet
Use ³Get-Location´ to show current directory.
Get-Location<enter>
Using Alias and CMD Command.
gl<enter>
pwd<enter>
Example 3. Creating files and Directories
Use ³New-Item´ cmdlet to create a New Directory.
New-Item -Path C:\NewFolder -Type Directory<enter>
A cool thing about PoweShell, it will assist you when you leave out required information.
For example, let¶s say your creating the directory in the example above but you forget
the -Type paramter.
ëew-Item -Path C:\ëewFolder<enter>
PowerShell will prompt you for the missing parameter«
Type:
Continuing with the ³New-Item´ cmdlet, let¶s create a file in our new directory.
New-Item -Path C:\NewFolder\NewFile.txt -Type File<enter>
Example 4. Move ëewFile to the root of ³C:\´ using ³Move-Item´ cmdlet
Move-Item -Path C:\NewFolder\NewFile.txt C:\<enter>
Verify file moved.
Get-ChildItem N*<enter>
Example 5. Renaming Files and Directories
Let¶s rename the NewFile.txt to RenFile.txt.
Rename-Item -Path C:\NewFile.txt RenFile.txt<enter>
Verify the file has been renamed.
Get-ChildItem R*<enter>
Rename Directroy NewFolder to RenFolder.
Rename-Item -Path C:\NewFolder RenFolder<enter>
Set-Location Function:<enter>
Get-ChildItem<enter>
Functions Provider
R
'
Image 5.10 displays the Functions that are defined in PowerShell. ³Name´ is the name
given to the function and the ³Definition´ is the code that runs when we call the name.
What does it mean to ³call´ a function? In PowerShell, we are only required to type a
function name and the corresponding code will execute. For example, typing ³set-
Location C:´ navigates to the root of C: drive. We can also navigate to the root of C:
just by typing(calling) the ³C:´ function name. PowerShell runs the ³Set-Location C:´
code which places us at the root of C: drive. Let¶s take a look at another example.
Example 2. Viewing the Code of a PowerShell Function
1. We are going to use the ³Get-Content´ cmdlet to view the code block of the
Clear-Host Function.
Get-Content Clear-Host<enter>
Output:
$spaceType = [System.Management.Automation.Host.BufferCell]; $space
= [Sys
tem.Activator]::CreateInstance($spaceType); $space.Character = µ µ;
$space
.ForegroundColor = $host.ui.rawui.ForegroundColor;
$space.BackgroundColor
= $host.ui.rawui.BackgroundColor; $rectType =
[System.Management.Automatio
n.Host.Rectangle]; $rect = [System.Activator]::CreateInstance($rectType);
$rect.Top = $rect.Bottom = $rect.Right = $rect.Left = -1; $Host.UI.RawUI.S
etBufferContents($rect, $space); $coordType =
[System.Management.Automatio
n.Host.Coordinates]; $origin =
[System.Activator]::CreateInstance($coordTy
pe); $Host.UI.RawUI.CursorPosition = $origin;
So my guess is that you would be more inclined to calling the ³Clear-Host´ function than
actually typing the code required to clear the screen. Can you see how calling a function
reduces the amount of code written in the script?
Before getting in too deep and making your head swim, I¶m going to end this discussion
about this Provider until we talk more about PowerShell Functions and Scripting. For
now, let¶s move on to the coolest PowerShell Provider in the world!!!
Vc $
#c
If you ever wanted to work with the registry with the same ease as working with the file
system, your wish has come true. The Registry Provider allows us to connect to two
PSDrives; HKCU (HKEY_CURRENT_USER) and HKLM (HKEY_LOCAL_MACHINE).
With the Registry Provider we can:
1. The two PSDrives we can connect to are HKLM and HKCU. Verify this by
checking which PSDrives are available.
Get-PSDrive<enter>
R
Registry Provider
Set-Location HKLM:<enter>
Set-Location HKLM:\Software<enter>
Get-ChildItem<enter>
R
HKLM
We¶re all familiar with the warnings of making changes to the Registry. Since I wish to
only help and do no harm, I¶m not going to provide examples of making registry
changes. Just note that you can use the same cmdlets used when working with all
PowerShell Providers.
Cmdlet Alias Cmd Commands Descritption
Get-Location gl pwd Current Directory.
Set-Location sl cd, chdir Change current directory.
Copy-Item cpi copy Copy Files.
Remove-Item ri del Removes a File or directory.
Move-Item mi move Move a file.
Rename-Item rni rn Rename a file.
Creates a new empty file or
New-Item ni n/a
folder.
Clear-Item cli n/a Clears the contents of a file.
Set-Item si n/a Set the contents of a file.
Mkdir n/a md Creates a new directory.
Sends contents of a file to the
Get-Content gc type
output stream.
Set-Content sc n/a Set the contents of a file.
I will show you one very cool example of using the ³Get-ChildItem´ cmdlet to list
installed Hot Fixes on a system:
Get-ChildItem -Path ³HKLM:\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\HotFix´<enter>
ëote: In the -Path parameter, quoting the path statement was required as there is a
space between Windows and NT.
You should now see a list of ³Hot Fixes´ that have been installed on the system. Staying
with the theme of this PowerShell tutorial, I¶m going to use the ³CD´ alias to navigate to
one of the ³Hot Fix´ keys. Choose any hot fix you wish to enumerate.
CD KB888240<enter>
Next question should be« How do we enumerate the information inside the registry
key? Simply use the ³Get-ItemProperty´ cmdlet.
Get-ItemProperty .<enter>
I used the ³.´ as we are currently working within the registry path location. You can also
get the properties using the -Path parameter. Here¶s the example:
Get-ItemProperty -Path ³HKLM:\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\HotFix\KB888240Ǝ<enter>
Now we see all the properties, how about just a specific property?
Get-ItemProperty . -Name Comments<enter>
Create and Remove a ëew Registry Key and Property
First, Let¶s work from the root of SOFTWARE.
Set-Location -Path HKLM:\SOFTWARE<enter>
Create new registry Key and Default Property using ³New-Item´ cmdlet from the table.
New-Item -Name Test -Value ³This is a test string´<enter>
Verify ³Test´ key exists
Get-ChildItem T*<enter>
Verify the default property has the string value we created.
Get-ItemProperty -Path .\Test<enter>
Next, Let¶s delete the new key using the ³Remove-Item´ cmdlet.
Remove-Item Test<enter>
Verify the key has been removed.
Get-ChildItem T*
Using the Registry Provider we are able to navigate, enumerate, create, and delete
registry items just like files and folders.
Real-World Example: An associate of mine started working for a banking institution.
We¶re talking multiple locations around the United States. His boss didn¶t like the
naming convention for network printers as they provided no clue of printer type or
location. His task was to create new print queues (with a new naming convention) and
cut all the user over to the new print queues. Because he was dealing with multiple
locations, it was impossible for a tech to be on-site to remap clients to the new print
queues. Another requirement was to automate the process so that clients would not
experience down time when printing. He told the boss« ³No Problem.´
I¶m only going to describe what he did in pseudo code as it would take another tutorial
to examine his script. Network Print Queues are stored in the registry as a UNC
(\\PrintServer\PrinterName). He created a second print queue for each printer on all his
print servers. Created a printer script which used an array to store the old printer names
and their new counterparts. The script would change the registry setting from
\\PrintServer\OldQueue to \\PrintServer\NewQueue while also preserving the default
printer setting. He replicated the new script to all Domain Controllers in his environment
and edited the company¶s logon script to call the printer script. When the printer script
runs, it looks at the registry keys and if it finds reference to an old print queue name, it
would edit that key with the new value. He allowed the script to run for a month or two to
ensure that everyone using shared PCs would get the new print queues. After that time
period, if he received calls from clients stating they could not connect to a new printer,
he would just turn on the print script (uncomment it in the main logon script) and ask the
client to re-logon the Domain.
This example shows just how powerful connecting the registry can be. Needless to say,
his boss thought he was brilliant (which he is) an sent him off to Hawaii (ok - maybe not!
But it is a nice thought).
Vc % c
What is a variable? I like to think of a variable as a ³little box´ that is used to store
information. The Variable Provider shows us which PowerShell and user defined
variables are available. Again, we will be working with variables when scripting, so this
is just an introduction.
Example 1. Connect to the PSDrive Variable: and Show a List of Available
Variables
Connect to the PSDrive.
Set-Location Variable:<enter>
Use.. What Command to list variables?
Get-ChildItem<enter>
Example 2. List the Information in the PSHome Variable
In PowerShell, variables are preceded by the dollar sign character ($). However, the list
of variables in example 1. don¶t show a ³$´ sign. To view the information stored in the
PSHome variable, just add the ³$´ before the variable name.
$PSHome<enter>
The $PSHome variable holds the information of the PowerShell installation path. Check
out the information stored in other variables such as the $Profile and $Home variables.
Example 3. Create a User Defined Variable
There are a few ways to create variables. Since were talking about File System cmdlets
used with providers, sticking with theme we would do the following:
New-Item MyVar -Value ³This is my new variable.´<enter>
You can also use the ³Set-Variable´ cmdlet to accomplish the same:
Set-Variable MyVar2 -Value ³This is my second variable.´<enter>
This last example is most commonly used when scripting. You will find yourself using
this example more than the others:
$MyVar3 = ³This is my third variable.´<enter>
Let¶s sort the listing of variables by name and verify our newly created variables exist.
Get-ChildItem | Sort {$_.Name}<enter>
Do you see MyVar, MyVar2, and MyVar3 user-defined variables?
Example 4. Remove Variables
Let¶s use the ³Remove-Item´ cmdlet to remove the variables we created:
Remove-Item MyVar,MyVar2,MyVar3<enter>
Let¶s verify the variables have been removed:
Get-ChildItem | Sort {$_.Name}<enter>
By now your asking yourself, what is $_.ëame? We can see that $_ must be a variable
(all variables are noted by the dollar sign in PowerShell)« and it is. As defined,
variables hold information. $_ is a special variable the holds the object piped from the
³Get-ChildItem´ cmdlet. The .ëame is the Name Property of the object. I know your sick
of me saying this but, we will explore script blocks in a later PowerShell tutorial.
One more PowerShell Provider to go«
Vc
c
Here is the last PowerShell Provider we need to cover. Using ³Get-PSDrive´ cmdlet we
can see that we need to connect to the ³cert´ drive.
Example 1. Set Location to the Cert PSDrive and List all the Certificates on the
System
Set-Location cert:<enter>
Get-ChildItem<enter>
This command truncates the ³StoreNames´ for good reason, there are a lot of entries. If
you want a report of all certificates on a system may I suggest the following:
Get-ChildItem -Recurse | Export-CSV ³C:\Certificates.csv´<enter>
View results:
Invoke-Item ³C:\Certificates.csv´<enter>
Certificates
R
Wow!!! we made it to the end of this PowerShell Training session. The basic concepts
to take away from this tutorial are that PowerShell Providers allow us to use common
cmdlets outside of the PowerShell environment. We only have to learn a few cmdlets,
shortening the learning curve, to be affective working with:
î PowerShell Aliases
î Environment Variables
î Files and directories
î Functions
î The Registry
î Variables in PowerShell
î Certificates
Hope you enjoyed this tutorial, use the comment section for any questions or
comments. See you in the next PowerShell Tutorial«
?
2
c "
c
c
%c "
&
"
2
?
It¶s time to take what we have learned and apply it to writing scripts. The plan is six new
and exciting PowerShell tutorials to explain the fundamentals of the PowerShell
scripting language. Here is what will be covered:
Conditional Logic
Tutorial 8. explains:
Loops
Tutorial 9. gets loopy:
In this PowerShell training session we are going to discuss storing, retrieving, and
manipulating data within PowerShell. PowerShell enables us to store information using
the following methods:
In PowerShell, variables can contain text strings, integers, and even objects (complete
with properties and methods). Special variables exist, which are pre-defined within
PowerShell. We have worked with one of these variables ($_) in a prior tutorial.
Special Variable Examples
î $_ - Contains the current pipeline object, used in script blocks, filters, and
the where statement.
î $Args - Contains an array of the parameters passed to a function.
î $Error - Contains objects for which an error occurred while being
processed in a cmdlet.
î $Home - Specifies the user¶s home directory.
î $PsHome - The directory where the Windows PowerShell is installed.
To view the complete list of Special Variables in PowerShell, type the following:
Get-Help about_automatic_variables<enter>
In VBScript, we have to declare variables before using them. For example:
dim strComputer
dim strUser
dim intDate
strComputer = ³MyComputer´
etc«
In PowerShell, ALL variable names must start with the ³$´ character. Once data is
assigned to a PowerShell variable, it¶s automatically declared. The ³=´ operator is used
to assign data to a variable. Here is a simple example of creating a variable in
PowerShell:
$strComputer = ³Computer1Ǝ<enter>
There is a ³Set-Variable´ cmdlet that can also be used:
Set-Variable -Name strUser -Value ³John Doe´<enter>
You can use virtually any variable name you choose, names are not case sensitive.
ëote: there are illegal characters such as; ! @ # % & , . and spaces. PowerShell will
throw an error if you use an illegal character.
I stated virtually any name as PowerShell does have a set of keywords that are
reserved and cannot be used as variable names:
î break
î continue
î do
î else
î elseif
î filter
î foreach
î function
î if
î in
î return
î switch
î until
î where
î while
When naming variables, I continue to use the caMel case naming convention I became
accustomed to in VBScript. The first part of the name (str) reminds me that the variable
I¶m working with contains ³text string´ data. If I were working with numbers, it might look
like something this ³$intMegaBytes.´ Again, you can use any naming convention you
wish.
Let¶s verify that the $strComputer variable is holding the data we assigned to it.
Write-Output $strComputer<enter>
-or just type-
$strComputer<enter>
$strComputer Variable
'
The output verifies the data in the $strComputer variable is the ³Computer1Ǝ text string.
Go ahead and verify the data value for the ³strUser´ variable.
$strUser<enter>
Did you get John Doe for the output? Yes« great! No?« I knew you were going to skip
the long version of using the ³Set-Variable´ cmdlet.
ëote: If you use the ³Set-Variable´ cmdlet and specify the -Name parameter, you do not
use the ³$´ character when defining variables. Most of the time I use ($strComputer =
³computerName´) to create variables. Just be conscious of this rule when using the
³Set-Variable´ cmdlet.
Working with Strings
A [sting] is a ³text string´ data type. There are many data types that we will be working
with in PowerShell:
Type Description
[int] 32-bit signed integer
[long] 64-bit signed integer
[string] Fixed-length string of Unicode characters
[char] A Unicode 16-bit character
[byte] An 8-bit unsigned character
[bool] Boolean True/False value
[decimal] An 128-bit decimal value
[single] Single-precision 32-bit floating point number
[double] Double-precision 64-bit floating point number
[xml] Xml object
[array] An array of values
[hashtable] Hashtable object
Yep, we will be discussing them all at some point«
String Concatenation
Concatenation is the process of joining together two strings. Here is an example:
$strA = ³Hello ³<enter>
$strB = ³World!´<enter>
$strC = $strA += $strB<enter>
$strC<enter>
We used += to join together variables $strA and $strB and store the new ³text string´ in
variable $strC. The output from $strC is Hello World!
Most of the time you will see two strings joined together by using just the ³+´ operator.
Like so; $strC = $strA + $StrB. Both result in the same output.
Aside from joining strings we can also replace words using the -replace parameter.
$strA = ³Go east young man!´<enter>
$strB = $strA -replace ³east´, ³west´<enter>
$strB<enter>
PowerShell follows the rules of math. Equations are read from left-to-right, multiplication
and division are preformed then addition and subtraction.
$x = 10 * 2 / 5 * 2 + 5 * 5<enter>
$x<enter>
What answer did you get? Hopefully 33.
What about:
$x = 10 * 2 / 5 * (2 + 5) * 5<enter>
$x<enter>
Parenthesis can be used to alter the order of the mathematical rule. O.k. enough math
class.
ëote: PowerShell has two additional operators that you will use frequently. Make a
mental note of these operators as you will be using them often in your script writing.
Examples:
$x = 1<enter>
$x<enter>
1
$x++<enter>
$x<enter>
2
$x++<enter>
$x<enter>
3
$x±<enter>
$x<enter>
2
We will work with more data types when the advanced PowerShell tutorials are
launched.
Here are nine exercises to complete. See if you can get through them all without looking
at the answers. Answers provided below the exercise:
1. Create a variable named $strComputer and assign the files server name
FSrv01.
2. Create a variable named $x and assign the number 7.
3. Create a variable named $y, assign the data type and number 11.
4. Create a variable named $Pi, assign the data type and number 3.14
5. Concatenate the following variables, strA = ³This is a ´ and strB = ³text
string.´
6. Using two variables, subtract 5 from 9.
7. Using two variables, add 5 and 9.
8. Assign the number 1 to variable $x and increment by 1.
9. Get the answer for the following equation. 5 * 2 / 10 + 7 / 3 * 2.
Answers:
1. $stromputer = ³FSrv01Ǝ
2. $x = 7
3. [int]$y = 11
4. [decimal]$Pi = 3.14
5. strA + strB -or- strA += strB
6. $x = 9<enter> $y = 5<enter> $x - $y<enter>
7. $y + $x<enter>
8. $x = 1<enter> $x++<enter> $x<enter>
9. $x = 5 * 2 / 10 + 7 / 3 * 2<enter> $x = 6
c #
Variables can also store arrays which by definition are an indexed list of values. Each
item is assigned a unique index number. The first item in an array is assigned the value
of (0), the next item (1), then (2), and so on. One of the more popular uses of an array is
to run a script against remote computers. If you¶ve looked at the PowerShell scripts in
the Microsoft Script Center Repository, notice that a lot of scripts only run on the local
computer by using strComputer = ³.´ variable. ³.´ means the local computer the script
is running on. You could run the script on a remote computer by modifying the code like
this strComputer = ³RemoteComputerëame´. But, what if you want to run the script
against multiple computers on your network? Ok« besides using a logon script! In
essence a logon script still runs locally and you have limited control over when it runs.
The answer is by using an array!
To create an array, we create a variable and assign the array. Arrays are noted by the
³@´ symbol. Let¶s take the discussion above and use an array to connect to multiple
remote computers:
$strComputers = @(´Server1Ǝ, ³Server2Ǝ, ³Server3Ǝ)<enter>
We now have three values stored in the $strComputers variable. ëote: Since I am
working with string values, I¶m quoting. Also each array value is separated by a comma.
How to list the values in the array:
$strComputers<enter>
List the number of items within the array using the count property.
$strComputers.Count<enter>
Now that we know there are three elements within the array, we can list an item by it¶s
index number. Remember, array index numbers start at 0. List values by their index
number:
$strComputers[0]<enter>
$strComputers[1]<enter>
$strComputers[2]<enter>
We can also modify elements in an array. Here I¶m modifying an element in an existing
array by providing the index number and the new string value. This changes the item
Server3 to Server4.
$strComputers[2] = ³Server4Ǝ<enter>
Verify the element was modified:
$strComputers<enter>
Using the + operator, we can combine arrays:
$x = @(1, 2, 3, 4, 5)<enter>
$y = @(6, 7, 8, 9, 10)<enter>
$z = $x + $y<enter>
$z<enter>
Back to our discussion on using arrays to get information from multiple computers. Here
is a typical script taken from the Microsoft Script Repository that enumerates the BIOS
information on the (strComputer = ³.´) local computer. ëote: you don¶t have to copy the
following script code into a .ps1 (PowerShell) script file to run. Just copy and paste the
code into the PowerShell Console; to paste in PowerShell just do a right mouse click.
When the code has been copied into the shell, just hit <enter> twice to get the results.
Just another cool thing you can do with PowerShell«
$strComputer = ³.´
$colItems = get-wmiobject -class Win32_BIOS -namespace root\CIMV2 -comp
$strComputer
foreach ($objItem in $colItems) {
write-host ³BIOS Characteristics: ´ $objItem.BiosCharacteristics
write-host ³BIOS Version: ´ $objItem.BIOSVersion
write-host ³Build Number: ´ $objItem.BuildNumber
write-host ³Caption: ´ $objItem.Caption
write-host ³Code Set: ´ $objItem.CodeSet
write-host ³Current Language: ´ $objItem.CurrentLanguage
write-host ³Description: ´ $objItem.Description
write-host ³Identification Code: ´ $objItem.IdentificationCode
write-host ³Installable Languages: ´ $objItem.InstallableLanguages
write-host ³Installation Date: ´ $objItem.InstallDate
write-host ³Language Edition: ´ $objItem.LanguageEdition
write-host ³List Of Languages: ´ $objItem.ListOfLanguages
write-host ³Manufacturer: ´ $objItem.Manufacturer
write-host ³Name: ´ $objItem.Name
write-host ³Other Target Operating System: ´ $objItem.OtherTargetOS
write-host ³Primary BIOS: ´ $objItem.PrimaryBIOS
write-host ³Release Date: ´ $objItem.ReleaseDate
write-host ³Serial Number: ´ $objItem.SerialNumber
write-host ³SMBIOS BIOS Version: ´ $objItem.SMBIOSBIOSVersion
write-host ³SMBIOS Major Version: ´ $objItem.SMBIOSMajorVersion
write-host ³SMBIOS Minor Version: ´ $objItem.SMBIOSMinorVersion
write-host ³SMBIOS Present: ´ $objItem.SMBIOSPresent
write-host ³Software Element ID: ´ $objItem.SoftwareElementID
write-host ³Software Element State: ´ $objItem.SoftwareElementState
write-host ³Status: ´ $objItem.Status
write-host ³Target Operating System: ´ $objItem.TargetOperatingSystem
write-host ³Version: ´ $objItem.Version
write-host
}
Now we want the same information from multiple remote computers. This time you
choose which ones. Create an array with two (or more) computers, FYI - you must have
local admin rights on each computer to run the script. Use notepad and change the
computer names in the array. Copy and paste your new code into PowerShell.
$strComputer = @(´computer1Ǝ, ³computer2Ǝ, ³computer3Ǝ)
$colItems = get-wmiobject -class Win32_BIOS -namespace root\CIMV2 -comp
$strComputer
foreach ($objItem in $colItems) {
write-host ³BIOS Characteristics: ´ $objItem.BiosCharacteristics
write-host ³BIOS Version: ´ $objItem.BIOSVersion
write-host ³Build Number: ´ $objItem.BuildNumber
write-host ³Caption: ´ $objItem.Caption
write-host ³Code Set: ´ $objItem.CodeSet
write-host ³Current Language: ´ $objItem.CurrentLanguage
write-host ³Description: ´ $objItem.Description
write-host ³Identification Code: ´ $objItem.IdentificationCode
write-host ³Installable Languages: ´ $objItem.InstallableLanguages
write-host ³Installation Date: ´ $objItem.InstallDate
write-host ³Language Edition: ´ $objItem.LanguageEdition
write-host ³List Of Languages: ´ $objItem.ListOfLanguages
write-host ³Manufacturer: ´ $objItem.Manufacturer
write-host ³Name: ´ $objItem.Name
write-host ³Other Target Operating System: ´ $objItem.OtherTargetOS
write-host ³Primary BIOS: ´ $objItem.PrimaryBIOS
write-host ³Release Date: ´ $objItem.ReleaseDate
write-host ³Serial Number: ´ $objItem.SerialNumber
write-host ³SMBIOS BIOS Version: ´ $objItem.SMBIOSBIOSVersion
write-host ³SMBIOS Major Version: ´ $objItem.SMBIOSMajorVersion
write-host ³SMBIOS Minor Version: ´ $objItem.SMBIOSMinorVersion
write-host ³SMBIOS Present: ´ $objItem.SMBIOSPresent
write-host ³Software Element ID: ´ $objItem.SoftwareElementID
write-host ³Software Element State: ´ $objItem.SoftwareElementState
write-host ³Status: ´ $objItem.Status
write-host ³Target Operating System: ´ $objItem.TargetOperatingSystem
write-host ³Version: ´ $objItem.Version
write-host
}
For more information on building arrays to enumerate remote computers, here is a very
cool article I¶ve written: 3 easy steps to get information from remote computers.
OV
A Hash table is also known as a dictionary. It is an array that allows you to store data in
a ³key-value´ pair association. The ³key´ and ³value´ entries can be any data type and
length. The elements must be quoted if they contain a space.
Just like an array we designate a hash table with the @ symbol. There are differences,
array elements are enclosed in parenthesis () where hash ³key-value´ pairs are
enclosed in curly brackets {}. Hash elements are separated by the semi-colon.
Creating a hash of users associated with their employee number:
$EmpNumbers = @{´John Doe´ = 112233; ³Dave Davis´ = 223344; ³Justine Smith´ =
334455}<enter>
Verify the hash table was created:
$EmpNumbers<enter>
Hast Table
R
Looks like a mini-database. How would we find John Doe¶s employee number?
$EmpNumbers["John Doe"]<enter>
Add a new employee record:
$EmpNumbers["Rose Jones"] = 445566<enter>
Verify the creation of new ³key-value´ pair.
$EmpNumbers<enter>
Delete an employee record:
$EmpNumbers.Remove(´Rose Jones´)<enter>
Verify record deletion:
$EmpNumbers<enter>
To Remove all records in the hash table, we use the clear method:
$EmpNumbers.Clear()<enter>
To recap, variables are items of information that we store for later retrieval. Arrays
consist of numerous values that can be stored in a variable. Hash tables are associative
arrays that use a ³key-value´ pairs. Since a hash table is like a dictionary, it is much
easier to find values within the array (as there is an association created). Standard
arrays are indexed starting from the number 0. This makes it difficult to find values,
unless you¶re a large brain and can tell me what value was assigned to index 245.
Thanks again for your time« In our next PowerShell training session we are going to
talk about using Conditional logic. See you in the next tutorial.
As with other programming languages, PowerShell is a dynamic scripting language.
Script code can be executed based on conditions that exist or occur. For example, a
script might prompt for user input and run a block of code based on the data supplied by
the user. A process or application may stop running, triggering an action within a script.
Conditional Logic allows us to write scripts in a complex environment, it adds the
intelligence required to create decision-making scripts.
Launch PowerShell and let's get started«
We are going to compare data using the following PowerShell Comparison and Logical
Operators.
Table 1: PowerShell Comparison Operators:
Operator Description
-eq Equal to
-lt Less than
-gt Greater than
-ge Greater than or Eqaul to
-le Less than or equal to
-ne Not equal to
I'm not going to join in the great debate over why these operators where chosen, they
exists within PowerShell and must be used. Special note: When comparing text strings,
by default PowerShell is not case-sensitive. "TOM" and "tom" would compare "equal to"
(-eq). However, you can force PowerShell to compare values based on case-sensitivity.
By appending an "i" to the operator, you're telling PowerShell to be "case-insensitive."
Appending a "c" forces PowerShell to compare as "case-sensitive."
Examples:
Tom -eq TOM. The result is "True"
Tom -ieq TOM. The result is "True"
Tom -ceq TOM. The result is "False"
Table 2: PowerShell Logical Operators:
Operator Description
-not Not
! Not
-and And
-or Or
Now that we have the table listings of Operators, let's do some examples to show their
use and results.
7 -eq 7<enter>
Result is "True"
7 -ne 7<enter>
Result is "False"
7 -lt 10<enter>
Result is "True"
7 -gt 10<enter>
Result is "False"
"Tom" -eq "tOm"<enter>
Result is "True"
"Tom" -ceq "tOm"<enter>
Result is "False"
I'm going to skip the logical operators for now, we'll get back to them in a moment.
What's important to understand is each code snippet is providing a result, either True or
False. The results are used in the decision-making process within PowerShell scripts.
Now that we have results, what do we do with them? We need a way to apply
comparison results with conditional logic (the decision-making process). PowerShell
supports two logic statements to help out:
Let's do a simple script that shows the if statement in action. Copy the code into
clogic.ps1 file and save it to the "MyScripts" directory. Run the script:
"C:\MyScripts\clogic.ps1<enter>" -or- type ".\clogic.ps1 if you are currently working in
the MyScripts directory.
$x = 2 #creates a variable x and assigns 2 as the value
if ($x -eq 5) {Write-Host "Hello my name is Bob"}
elseif ($x -eq 4) {Write-Host "Hello, my name is Sue"}
elseif ($x -eq 2) {Write-Host "Hello, my name is Troy"}
elseif ($x -gt 1) {Write-Host "Hello, my name is Mary"}
else {"I have no idea what my name is?"}
The result should be Hello, my name is Troy as the condition ($x -eq 2) resulted in a
True value and executed the script block {}. But I purposely threw you a curve ball.
Notice that the last elseif statement ($x -gt 1) would also result in a True condition, so
why doesn't it's script block get executed? This is by design, once an if statement
condition results in a True value the associated script block is executed and
PowerShell stops testing subsequent conditions. The way around this is to use a switch
statement which we will discuss in this PowerShell training session.
Real-World Example:
Sometimes different Operating Systems use different WMI classes and/or properties. I
ran into this difference when attempting to enumerate printers on Windows XP,
Windows 2003, and Windows 2000. I used an if statement to test the OS version and
based on the version, PowerShell would run the code block associated for each OS.
Here's the code I used:
Copy the following code into a .ps1 script file. Name it PrintReport.ps1 and execute the
script.
$strComputer = Read-Host "Printer Report - Enter Computer Name"
$OS = Get-WmiObject -Class win32_OperatingSystem -namespace "root\CIMV2" `
-ComputerName $strComputer
# if statement to run code for Windows XP and Windows 2003 Server.
if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790"))
{
write-host "Computer Name: " $strComputer
#nested if statement
if ($OS.Version -eq "5.1.2600") {write-host "OS Version: Windows XP"}
elseif ($OS.Version -eq "5.2.3790") {write-host "OS Version: Windows 2003"}
$colPrinters = Get-WmiObject -Class win32_Printer -namespace "root\CIMV2" `
-computerName $strComputer
foreach ($objPrinter in $colPrinters) {
write-host "Name: " $objPrinter.Name
write-host "Description: " $objPrinter.Description
write-host
}
}
# if statement to run code for Windows 2000 Server
elseif ($OS.Version -eq "5.0.2195")
{
write-host "Computer Name: " $strComputer
write-host "OS Version: Windows 2000 Server"
$colPrinters = Get-WmiObject -Class win32_PrintJob -namespace "root\CIMV2" `
-computername $strComputer
foreach ($objPrinter in $colPrinters) {
write-host "Name: " $objPrinter.Name
write-host "Description: " $objPrinter.Description
write-host
}
}
# if OS not identified
else {write-host "The OS for: $strComputer is not supported."}
write-host "±END OF REPORT±"
When the script is executed, you are prompted to enter the computer name you wish to
enumerate. By adding the "Read-Host" cmdlet, you're now able to enumerate other
computers on your network. Pretty cool stuff going on here, let's break it down.
Step 1. $strComputer = Read-Host "Printer Report - Enter Computer ëame"
Creates a variable called $strComputer and assigns a value supplied from user input.
Step 2. $OS = ret-WmiObject -Class win32_OperatingSystem -namespace
"root\CIMV2" `
-Computerëame $strComputer
Creates the variable "$OS" and assigns the win32_OperatingSystem class object.
Something else to look at. Even though it looks like two lines of code, it's actually one
line of code. The "`" escape character means to continue as one line. Used for keeping
scripts legible should you run out of space. PowerShell reads the line as:
$OS = Get-WmiObject -Class win32_OperationSystem -namespace "root\CIMV2" -
Computername $strComputer
Step 3. if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790"))
Here is where we talk about Logical Operators.
Operator Description
-not Not
! Not
-and And
-or Or
What you need to know. The Not operators -not and ! (both mean NOT) allow you to
modify the results of a condition. For example:
if (1 -eq 1) - results in a True value and runs the script block.
if (!(1 -eq 1) - results in a False value and skips the script block.
The -or operator means at least one of the conditions must be True to execute the
script block.
For example:
if ((1 -gt 2) -or (2 -gt 1)) - One of the conditions are True so, it's associated script block
will execute.
The -and operator means that all conditions must be True to execute the script block.
Example:
if ((1 -ge 1) -and (2 -ge 1)) - Both conditions are True, script block executes.
if ((1 -ge 1) -and (2 -le 1)) - The first condition is True, whereas the second is False.
The script block is skipped.
Step 4. {
write-host "Computer ëame: " $strComputer
#nested if statement
if ($OS.Version -eq "5.1.2600") {write-host "OS Version: Windows XP"}
elseif ($OS.Version -eq "5.2.3790") {write-host "OS Version: Windows 2003"}
$colPrinters = ret-WmiObject -Class win32_Printer -namespace
"root\CIMV2" `
-computerëame $strComputer
foreach ($objPrinter in $colPrinters) {
write-host "ëame: " $objPrinter.ëame
write-host "Description: " $objPrinter.Description
write-host
}
}
In step 3. if one of the conditions are True the script block in step 4. is executed. The
script block writes the following information to the screen:
If none of the conditions are True in step 3. PowerShell moves to the next if statement,
in this example that would be«
Step 5. elseif ($OS.Version -eq "5.0.2195")
If this condition results in a True value, the script block in step 6. is executed.
Step 6. {
write-host "Computer ëame: " $strComputer
write-host "OS Version: Windows 2000 Server"
$colPrinters = ret-WmiObject -Class win32_PrintJob -namespace
"root\CIMV2" `
-computername $strComputer
foreach ($objPrinter in $colPrinters) {
write-host "ëame: " $objPrinter.ëame
write-host "Description: " $objPrinter.Description
write-host
}
}
The result of the script block outputs the following information to the screen:
î Computer Name
î OS version
î Requested Property information of the win32_PrintJob class.
î Once the block completes, PowerShell skips to Step 8. and writes "±END
OF REPORT±" to let the end user know it has completed.
If the result in step 5. is False, PowerShell continues reading the script and finds the
"else" statement.
Step 7. else {write-host "The OS for: "$strComputer" is not supported."}
Outputs " The OS is not supported." Step 7. runs when all conditions in the script end
with a False value.
Step 8. write-host "±EëD OF REPORT±"
Let's you know the script has completed.
This example shows just how dynamic our scripts can be, based on conditions that exist
in our environment. And how we can write if statements to test those conditions and run
script blocks according to the results of those tests.
Now that we can input the $strComputer value, we can run this script on any remote
computer in the environment, as long we have local admin rights.
This next example has no real purpose other than demonstrating how the switch
statement works using the (test) expression with multiple True value results. Unlike if
statements, switch statements continue running when True value matches are found.
So it is possible that more than one code block will be executed. Copy and Paste the
code into the PowerShell shell. The results should be obvious, test expressions that
correctly equal 10 will run:
switch (10)
{
(1 + 9) {Write-Host "Congratulations, you applied addition correctly"}
(1 + 10) {Write-Host "This script block better not run"}
(11 - 1) {Write-Host "Congratulations, you found the difference correctly"}
(1 - 11) {Write-Host "This script block better not run"}
}
Conditional logic is the foundation for dynamic PowerShell script writing. We
successfully demonstrated how we can control the flow of a script base on conditional
responses. In the next PowerShell training session we are going to build on what we
have learned and introduce Loops, which takes flow control to the next level. See you in
the next PowerShell tutorial«
??
- !
- "
c
./
- "'
The last PowerShell training session introduced Conditional Logic, controlling execution
of script blocks with if and switch statements. Looping is a basic programming process
that allows us to repeat a command and process large amounts of data. Without this
ability, writing scripts would be tedious if not next to impossible.
Here are the loops we will be working with in this tutorial:
î do while - Script block executes as long as condition value = True.
î while - Same as ³do while.´
î do until - Script block executes until the condition value = True.
î for - Script block executes a specified number of times.
î foreach - Executes script block for each item in a collection or array.
In the code examples I¶m showing both ways of writing script blocks, either single line or
multi-line. Basically, the semi-colon (;) is a delimiter which allows us to separate
commands when writing code on a single line. The <carriage return> or <enter> delimits
code when using multiple lines. Either way is correct, it just depends on how long your
command statements become.
Real-World PowerShell example:
Scenario: Our company is having application issues with Notepad and it is mission
critical (LOL). It can actually be any application in your environment. We have been
asked to monitor the application and report any failure and log the time the failure
occurred.
Solution: We¶re going to use PowerShell to build a simple script to monitor the process
and report when a failure occurs. We¶re going to use a do while loop to watch the
³Responding´ property of the ³Get-Process´ object cmdlet. From an earlier PowerShell
training session I showed you how to get an object¶s properties and methods using the
³Get-Member´ cmdlet. As already stated, we will be using the ³Responding´ property for
our script.
Get-Process | Get-Member<enter>
Step 1. Close all current running versions of Notepad (if applicable).
Step 2. Write the script, save as NoteMon.ps1
#launches Notepad
Notepad
#Setup a do while loop that does nothing while property value is True.
do {}
While (get-process notepad | select -Property Responding)
#Code to run when loop stops (when notepad is closed)
$strTime = get-date
Write-Host ³The Application Notepad failed to respond on: $strTime´
Step 3. Run the NoteMon.ps1 script. Move notepad so that you can see the PowerShell
console.
Step 4. Exit or Close Notepad. The following is reported to the console window: ³The
Application Notepad failed to respond on: 10/25/2007 14:16:07Ǝ
Run the script again if you wish to restart the application. OK, so kind of a simple ³poor-
man¶s´ example of creating a monitoring system. Again, it¶s provided to help you
understand the looping concept and to give you a better real world example, rather than
just counting numbers.
Additional Reading:
Get-Content $PSHome\about_while.help.txt
The do until loop is the opposite of do while. It executes the code block until the
condition is True, in other words it runs while the condition value is False.
Syntax:
do {code block}
until (condition)
Example:
$i = 1
do {Write-Host $i; $i++}
until ($i -gt 5)
Output:
1
2
3
4
5
In this example the script block runs until the variable ($i) is incremented to the value of
6. Since 6 is greater than 5 the condition value becomes True, halting the loop from
executing further.
Real-World PowerShell Example:
Jerry Lee Ford¶s book (Microsoft Windows PowerShell Programming for the absolute
beginner) teaches PowerShell through game creation. It¶s a fun book that I recommend
for beginners, ³No Experience Required.´ You can read my review and pick up a copy
from this site. Jerry uses the do until loop to control the collection of user input. Here is
the example.
$strResponse = ³Quit´
do {$strResponse = Read-Host ³Are you sure you want to quit application? (Y/N)´}
until ($strResponse -eq ³Y´)
do until loop
R &'
Looking at the image, I copied the code into PowerShell and typed in numerous
responses. Each time the response did not equal ³Y´ the value of the condition was
False, therefore the script block was execute again and prompted the user for input.
The standard use of the for statement it to run the code block a specified number of
times.
Syntax:
for (initialization; condition; repeat)
{code block}
ëote: each of the three parameters are optional.
Example:
for ($i=1; $i -le 5; $i++)
{Write-Host $i}
Output:
1
2
3
4
5
Couple of things to take note:
î We delimit each parameter with a semi-colon (;). Don¶t confuse this with
separating commnads within a parameter using commas.
î We assigned the variable ($i=1) within the condition statement. Since
parameters are optional we could have assigned the variable outside of
condition statement. If you omit a parameter you are required to still use (;)
to delimit the parameters, example in BLUE. Here is the example showing
variable assignment outside the condition and how it would look.
$i=1
for (; $i -le 5; $i++)
{Write-Host $i}
Test what would happen if you omit a parameter forget to delimit (;) and attempt to run
the code.
$i=1
for ($i -le 5; $i++)
{Write-Host $i}
OK - don¶t panic, your in an infinite loop!!! Just type ³Ctrl + C´ to quit PowerShell
execution. Forgetting to delimit an omitted parameter can cause some unexpected
results, be careful.
If your code becomes large you can always delimit using <carriage return>.
for ($i=1
$i -le 5
$i++)
{write-host $i}
The for loop can also be used to process elements within an array.
$ints = @( 1, 2, 3, 4, 5)
for ($i=0; $i -le $ints.Length - 1; $i++)
{Write-Host $ints[$i]}
Do you know why the example sets the variable ($i) to 0 (zero) rather than 1?
Remember from the ³Arrays´ tutorial that arrays are indexed starting with the number 0.
If we set the variable to 1, our output would have been 2 3 4 5 <blank>.
The condition statement states, run script block as long as $i is less than or equal to 4.
$int.Length (length would be 5 entries in the array) so 5 - 1 = 4. When the Write-Host
cmdlet runs it gives us the following entries (0=1, 1=2, 2=3, 3=4, 4=5).
Output:
1
2
3
4
5
You should not have any issues working with arrays, as long as you remember that
indexing begins with 0 (zero). I dealt with this in VBScript and was hoping it would have
changed with PowerShell, maybe a later release?
Additional Reading:
Get-Content $PSHome\about_for.help.txt
The foreach loop description from the PowerShell Help file:
The foreach statement (also known as a foreach loop) is a language construct for
stepping through (iterating) a series of values in a collection of items.
The simplest and most typical type of collection to traverse is an array. Within a
foreach loop it¶s common to run one or more commands against each item in an
array.
ëote: Those writing VBScript code will have to get use to not using ³ëext´ as
PowerShell doesn¶t require the keyword to move to the next item in the collection.
Syntax:
foreach ($<item> in $<collection>)
{code block}
Sticking with our number example, let¶s see how the foreach loop works
$ints = @(1, 2, 3, 4, 5)
foreach ($i in $ints)
{Write-Host $i}
Output:
1
2
3
4
5
Looks a little like the for loop example presented earlier. However, notice that we are
not testing a condition. The foreach loop runs the script block against each element
within the array. It doesn¶t required testing a condition and it doesn¶t care how many
elements exist in the array. You point it and it runs. As stated in the help file, foreach
loop is the most typical statement used when working will arrays and collections.
I have presented many examples of foreach loops on this site. Most of the Microsoft
PowerShell Scripts in the Scripting Center use this loop.
Real-World Examples:
How about listing processor information.
$strComputer = ³.´
$colItems = get-wmiobject -class ³Win32_Processor´ -namespace ³root\CIMV2Ǝ `
-computername $strComputer
foreach ($objItem in $colItems) {
write-host ³Caption: ´ $objItem.Caption
write-host ³CPU Status: ´ $objItem.CpuStatus
write-host ³Current Clock Speed: ´ $objItem.CurrentClockSpeed
write-host ³Device ID: ´ $objItem.DeviceID
write-host ³L2 Cache Size: ´ $objItem.L2CacheSize
write-host ³L2 Cache Speed: ´ $objItem.L2CacheSpeed
write-host ³Name: ´ $objItem.Name
write-host
}
Listing disk information
$strComputer = ³.´
$colItems = get-wmiobject -class ³Win32_DiskDrive´ -namespace ³root\CIMV2Ǝ `
-computername $strComputer
foreach ($objItem in $colItems) {
write-host ³Description: ´ $objItem.Description
write-host ³Device ID: ´ $objItem.DeviceID
write-host ³Interface Type: ´ $objItem.InterfaceType
write-host ³Media Type: ´ $objItem.MediaType
write-host ³Model: ´ $objItem.Model
write-host ³Partitions: ´ $objItem.Partitions
write-host ³Size: ´ $objItem.Size
write-host ³Status: ´ $objItem.Status
write-host
}
Let¶s say we want to determine which processes are running on our computer.
foreach ($item in Get-Process)
{if ($item.Responding -eq ³True´){Write-Host $Item.Name}}
Just showing that we can add the conditional logic if statement within the foreach loop
to give us more control over the data we wish to retrieve.
Notice the code block - {{}} - what I¶ve done is called nesting. Perfectly legal and a
concept that we will discuss as you progress through these PowerShell Training
sessions.
Additional Reading:
Get-Content $PSHome\about_foreach.help.txt
In this example, the foreach statement iterates the $varB array. Each time
through the code block, the $i variable is incremented by 1. The if statement
inside evaluates to false the first two times through the loop. The third time
through the loop, $i equals 3 and the $val variable equals 30, at which point the
break statement runs and the foreach loop exits.
Additional Reading:
Get-Content $PSHome\about_break.help.txt
The Continue Statement
Excerpt from PowerShell help file:
In a script, the continue statement causes program flow to move immediately to
the top of the innermost loop controlled by any of these statements:
î?for
î?foreach
î?while
EXAMPLE
In this example, program flow returns to the top of the while loop if $ctr is equal to
5. The result is that all numbers between 1 and 10 except 5 are displayed.
while ($ctr -lt 10)
{
$ctr += 1
if ($ctr -eq 5){continue}
Write-Host $ctr
}
Note that in a for loop, execution continues at the first line in the loop. If the
arguments of the for statement test a value that is modified by the for statement,
an infinite loop can result.
In this PowerShell Training session you learned how to control script block flow using
loop processing. You were also able to process large amounts of data by looping
through a collection and enumerating properties of an object. In up-coming PowerShell
Let¶s start off be defining the terms:
î Function - A function allows you to name a block of code. The code block
can then be called (by its name) once or multiple times anywhere from
within your script.
î Filter - A Filter (as it sounds) takes large amounts of pipeline data and
displays only the results of interest to you.
c ¦
The main reason I use functions is script organization. It allows me the ability to call
script blocks multiple times within a script, cutting down on the amount of code writing to
accomplish my task. Not to mention it improves readability and makes complex
PowerShell scripts manageable. This PowerShell training session introduces the
concepts of a Function and a Filter. It is intended as an introduction, advance
techniques will be covered in the PowerShell advanced tutorials launched early next
year. With that being said, this tutorial will teach the concept of functions used for
modular scripting and how to build libraries of reusable code. We will also briefly talk
about filters.
Function Syntax:
Function(keyword) FunctionName (parameters) {script block}
The syntax uses the keyword Function, a FunctionName you provide, optional
parameters, and the script block.
Example 1. Create a Function called ³Time´ which runs the Get-Date cmdlet when
called.
Function Time {Get-Date}<enter>
Call the function by typing the FunctionName Time at the command prompt.
PowerShell Function
'
Simple stuff right! We defined a function using the ³Function´ keyword, named the
function ³Time,´ omitted the optional parameters, and assigned the Get-Date cmdlet
within the script block. Now let¶s start adding some parameters.
Passing Arguments to Functions
There are multiple ways to pass arguments to a function. I¶ll introduce some common
methods.
Ô( Passing Arguments in a comma separated list. Notice that the parameters
enclosed in parenthesis and separated by a comma, much like an array.
Function Add ($x, $y)
{
$Ans = $x + $y
Write-Host ³The Answer is $Ans´
}
Result
Copy the code into PowerShell and hit enter twice to get back to the command prompt.
Now, at the command prompt type the function and arguments for $x and $y variables:
Add 10 2<enter>
You should see the following result - The Answer is 12
'
Ô( Using the Param keyword. When using the Param keyword, notice that we
are defining the arguments within the scriptblock {}. The Param keyword must be the
first word inside the script block.
Function Add
{
param ($x, $y)
$Ans = $x + $y
Write-Host ³The Answer is $Ans´
}
Type - Add 10 12<enter>
Addition
'
Ô( If you recall from PowerShell Tutorial 7: Variables, Arrays, and Hash Tables
- There is a special variable $Args which contains an array of the parameters passed to
a function. Let¶s use this variable to show how we can pass an argument using string
expantion.
Function HAL {´What are you doing $args ?´}<enter>
Type in the FunctionName and an Argument:
HAL Dave
$Args
'
You can use multiple $Args variables to pass more than one parameter.
Example 2.
Function Add { $args[0] + $args[1] }<enter>
Type: Add 5 8
Multiple $Args
'
î Add - Since we did not send any arguments, the default was used for $x
and $y resulting in 0 + 0 = 0.
Next Type the following command which pipes the cmdlet output to the function we
defined:
Get-ChildItem -Path C:\ | FindFolder<enter>
$input Results
'
So, what are we doing here? We created a function call FindFolder which uses the
³Where-Object´ cmdlet to filter results based on the Name property. But what results is it
filtering? By itself it is just a function that does nothing until we send piped results to the
$input variable.
In this example we run the Get-ChildItem cmdlet telling it to start at the root of C:\ drive.
Simple enough, if we ran this command by itself we would get all the files and
directories just under the root of C: drive. By piping the information to our function, the
information is stored in the $input variable and only the folder named ³Windows´ is allow
to pass.
Let me show you how we can use a function to find a needle in the haystack. In this
example we will use a filter to find the Hosts file on a system.
Create the Function:
Function FindHosts
{
$input | Where-Object {$_.Name -eq ³hosts´}
}
Next, since were not sure if the directory containing the hosts file is a directory under of
the root of C: drive, we use the -recurse parameter to search all directories and
subdirectories under the root.
Use the following command:
Get-ChildItem -Path C:\ -Recurse | FindHosts<enter>
Eventually we find the hosts file and the location Directory:
Microsoft.PowerShell.Core\FileSystem::C:\Windows\system32\drivers\etc
I know that there are other ways to filter this information in PowerShell. The examples
provided were to show how this task can be accomplished using functions. Next let¶s
talk about filters.
c ¦
A Filter and a Function are essentially the same. The difference is how they process
data.
Filter Syntax:
Filter(Keyword) FilterName (parameters) {Script Block}
The syntax is the same as defining a Function except the ³Filter´ keyword is used, not
the ³Function´ keyword. A function uses the $input variable to contain pipeline
information whereas the filter uses a special variable $_ that contains the current
pipeline object. Here is where the Function and Filter differ; The function doesn¶t run
until all data has been stored in the $input variable, whereas the filter has immediate
access to the $_ variable and begins processing elements as they become available
(streaming).
Due to the $_ variable being able to process objects immediately, filters are widely used
and more efficient when large amounts of data are passed through the object pipeline.
For now, just take in the concepts. We will be working more with filters as we progress.
$2
Organizing Your Code
There are two methods I use to organize code:
1. Modular Scripting
2. Dot Sourcing
I find both methods useful but, most of the feedback I have gotten points to Dot
Sourcing as being the most commonly used method. I¶m going to show you both as I
believe both methods have there own unique value.
Modular Scripting Example
I¶m going to take two PowerShell script examples from the ³Microsoft Script Center´ and
show you how to create user-defined functions and call them from a script.
Say you want to inventory your system, gathering information about the Processor(s)
and Disk(s) available on the system. From the ³Microsoft Scripting Center´ you find
these two scripts.
List Processor Information:
$strComputer = ³.´
$colItems = get-wmiobject -class ³Win32_Processor´ -namespace ³root\CIMV2Ǝ `
-computername $strComputer
foreach ($objItem in $colItems) {
write-host ³Caption: ´ $objItem.Caption
write-host ³CPU Status: ´ $objItem.CpuStatus
write-host ³Current Clock Speed: ´ $objItem.CurrentClockSpeed
write-host ³Device ID: ´ $objItem.DeviceID
write-host ³L2 Cache Size: ´ $objItem.L2CacheSize
write-host ³L2 Cache Speed: ´ $objItem.L2CacheSpeed
write-host ³Name: ´ $objItem.Name
write-host
}
List Physical Disk Properties:
$strComputer = ³.´
$colItems = get-wmiobject -class ³Win32_DiskDrive´ -namespace ³root\CIMV2Ǝ `
-computername $strComputer
foreach ($objItem in $colItems) {
write-host ³Description: ´ $objItem.Description
write-host ³Device ID: ´ $objItem.DeviceID
write-host ³Interface Type: ´ $objItem.InterfaceType
write-host ³Media Type: ´ $objItem.MediaType
write-host ³Model: ´ $objItem.Model
write-host ³Partitions: ´ $objItem.Partitions
write-host ³Size: ´ $objItem.Size
write-host ³Status: ´ $objItem.Status
write-host
}
List Processor Information and List Disk Functions
In this example we are converting the ListProcessor and the ListDisk scripts, provided
by Microsoft, into functions. Here are the syntaxes I¶ve used: Function ListProcessor
{Script Block} -and- Function ListDisk {Script Block}
ëote: In PowerShell scripting, the ³#´ symbol is used for comments.
ListProcessor Function
# FileName: ListProcessor.txt
#
==================================================================
===========
# FUNCTION LISTINGS
#
==================================================================
===========
# Function: ListProcessor
# Created: [09/17/2007]
# Author: Jesse Hamrick
# Arguments:
#
==================================================================
===========
# Purpose: Provides Processor information
#
#
#
==================================================================
===========
function ListProcessor {
$colItems = get-wmiobject -class ³Win32_Processor´ -namespace ³root\CIMV2Ǝ `
-computername $strComputer
foreach ($objItem in $colItems) {
write-host ³Caption: ´ $objItem.Caption
write-host ³CPU Status: ´ $objItem.CpuStatus
write-host ³Current Clock Speed: ´ $objItem.CurrentClockSpeed
write-host ³Device ID: ´ $objItem.DeviceID
write-host ³L2 Cache Size: ´ $objItem.L2CacheSize
write-host ³L2 Cache Speed: ´ $objItem.L2CacheSpeed
write-host ³Name: ´ $objItem.Name
write-host
}
}
ListDisk Function
#* FileName: ListDisk.txt
#*=================================================================
============
#* FUNCTION LISTINGS
#*=================================================================
============
#* Function: ListDisk
#* Created: [09/15/2007]
#* Author: Jesse Hamrick
#* Arguments:
#*=================================================================
============
#* Purpose: Provides Disk Information
#*
#*
#*=================================================================
============
Function ListDisk {
$colItems = get-wmiobject -class ³Win32_DiskDrive´ -namespace ³root\CIMV2Ǝ `
-computername $strComputer
foreach ($objItem in $colItems) {
write-host ³Description: ´ $objItem.Description
write-host ³Device ID: ´ $objItem.DeviceID
write-host ³Interface Type: ´ $objItem.InterfaceType
write-host ³Media Type: ´ $objItem.MediaType
write-host ³Model: ´ $objItem.Model
write-host ³Partitions: ´ $objItem.Partitions
write-host ³Size: ´ $objItem.Size
write-host ³Status: ´ $objItem.Status
write-host
}
}
To verify functionality, you can copy and paste the functions into PowerShell and call
them from the command line by name. They will enumerate the data on the local host.
Building a Modular PowerShell Script
I¶m going to write a script that enumerates the processor(s) and disk(s) properties. I¶ll
³snap-in´ my newly created functions and use the ³SCRIPT BODY´ section of the
template to control the function calls. This may sound familiar to you if you have worked
with VBScript; subroutines and functions. Couple of differences:
Since I¶m working from ³C:\MyScripts´ directory I can use ³.\CPU.ps1Ǝ to call the scripts
in my code. Run the script:
C:MyScripts\ComputerInv_v1.1.ps1<enter>
This works great if we organize all of our scripts (code library) within the ³MyScripts´
directory. We can use the System Path to find the .ps1 files. The $PsHome variable
provides the installation path of PowerShell. By saving our scripts (code library) to this
directory, we only have to call the script name without possible path issues. By default,
PowerShell is installed using the following directory path:
C:\WIëDOWS\system32\WindowsPowerShell\v1.0
Example 2.
Step 1. Let¶s move ComputerInv_v1.1.ps1, CPU.ps1, and Disk.ps1 to the v1.0 directory.
Then modify the script body as follows:
#* FileName: ComputerInv_v1.1.ps1
#*=================================================================
============
#* Script Name: [Computer Inventory]
#* Created: [09/15/2007]
#* Author: Jesse Hamrick
#* Company: PowerShell Pro!
#* Email:
#* Web: http://www.powershellpro.com
#* Reqrmnts:
#* Keywords:
#*=================================================================
============
#* Purpose: Computer Invetory of CPU and Disk Properties
#*
#*
#*=================================================================
============
#*=================================================================
============
#* REVISION HISTORY
#*=================================================================
============
#* Date: [10/09/2007]
#* Time: [9:30 AM]
#* Issue: Dot-Source Example
#* Solution:
#*
#*=================================================================
============
#*=================================================================
============
#* SCRIPT BODY
#*=================================================================
============
# Create a string variable using the local computer.
$strComputer = ³.´
# Use Dot-Source to Call the ³ListProcessor´ function.
.{CPU.ps1}
# Use Dot-Source to Call the ³ListDisk´ function.
.{Disk.ps1}
#*=================================================================
============#* END OF SCRIPT: [Computer Inventory]
#*=================================================================
============
Here is the change in the script body - from .{.\scriptname.ps1} to .{scriptname.ps1}
Step 2. With the script files being placed in the PowerShell install directory, we only
have to type in the script name in which to run. The system path will find the where the
scripts are located and launch them. Let¶s launch the Computer Inventory script:
C:\MyScripts\ComputerInv_v1.1.ps1<enter>
Now, CD to the root of C: drive and attempt to run the script again:
C:\ComputerInv_v1.1.ps1<enter>
Did the script work? It will use the System¶s path to find the .ps1 files if necessary
Example 2. Calling a Function from another script file.
Using ³dot-sourcing´ you could create a library of functions. For example, let¶s say you
have one large file that contains over 100 separate functions you¶ve created.
Essentially, you maintain your function library in one or two documents. You can use dot
sourcing to read the file and call one or more functions written in the file. Click here to
find out how«
Which process should I use (Modular or Dot Source)?
Do I write functions within the script or do I call other scripts outside the main script?
There is really no wrong or right here, it depends on the situation. For example, let¶s say
you are writing a script for a client that will be utilizing functions in your script library.
You may wish to use the modular approach so that you can present your client will a
single script that is well document. If your writing scripts for you own environment,
chances are your using dot sourcing to call other functions as it takes less time and less
code to accomplish the task«
Conclusion
In this PowerShell Training session we have:
Again, the purpose of this tutorial was the introduction of Functions and Filters and how
they can assists with script organization. Functions and Filters provide many uses as we
will discover as we progress. These uses will become known throughout the rest of the
tutorials.
Until next time, happy scripting«
tutorials, we will be looking a Functions and more Script Block detail. See you then«
c
c
0
??