Powershell For The It Administrator, Part 1: Student Lab Manual (V1.1)
Powershell For The It Administrator, Part 1: Student Lab Manual (V1.1)
Powershell For The It Administrator, Part 1: Student Lab Manual (V1.1)
Administrator, Part 1
Student Lab Manual (v1.1)
Microsoft Confidential
Conditions and Terms of Use
Microsoft Confidential - For Internal Use Only
This training package is proprietary and confidential, and is intended only for uses described in the training materials.
Content and software is provided to you under a Non-Disclosure Agreement and cannot be distributed. Copying or
disclosing all or any portion of the content and/or software included in such packages is strictly prohibited.
The contents of this package are for informational and training purposes only and are provided "as is" without
warranty of any kind, whether express or implied, including but not limited to the implied warranties of merchantability,
fitness for a particular purpose, and non-infringement.
Training package content, including URLs and other Internet Web site references, is subject to change without notice.
Because Microsoft must respond to changing market conditions, the content should not be interpreted to be a
commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after
the date of publication. Unless otherwise noted, the companies, organizations, products, domain names, e-mail
addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real
company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should
be inferred.
Microsoft Confidential
Copyright and Trademarks
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering
subject matter in this document. Except as expressly provided in written license agreement from Microsoft, the
furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other
intellectual property.
Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under
copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted
in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose,
without the express written permission of Microsoft Corporation.
For more information, see Use of Microsoft Copyrighted Content at
http://www.microsoft.com/about/legal/permissions/
Microsoft®, Internet Explorer®, and Windows® are either registered trademarks or trademarks of Microsoft
Corporation in the United States and/or other countries. Other Microsoft products mentioned herein may be either
registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. All other
trademarks are property of their respective owners.
Microsoft Confidential
Microsoft | Services © 2012 Microsoft Corporation ITOE Educate
Microsoft Confidential
Page 4 of 361
Contents
LESSON 1 DEMONSTRATION : INTRODUCTION ............................................................................................... 9
Microsoft Confidential
Page 5 of 361
Microsoft Confidential
Page 6 of 361
LESSON 10 DEMONSTRATION : REGISTRY, EVENT LOG AND ACL MANAGEMENT ........................................ 301
Microsoft Confidential
Page 7 of 361
Microsoft Confidential
Page 8 of 361
Microsoft Confidential
Page 9 of 361
Objectives
After completing this lab, you will be able to:
Understand the basic use and capabilities of Windows PowerShell
Meet the pre-requisites and install Windows PowerShell
Run basic PowerShell commands
Use PowerShell help to get help about PowerShell commands
Prerequisites
To complete this lab, you need:
A Windows 7 workstation logged onto with administrator credentials. You can logon as
contoso\administrator. The password is P@ssword
Microsoft Confidential
Page 10 of 361
Microsoft Confidential
Page 11 of 361
Figure 1
3. Click one of the three rightmost buttons in the toolbar to adjust the pane arrangement.
This makes it easier to follow all examples.
Microsoft Confidential
Page 12 of 361
Figure 2
In this view,
1. Open the command file, or files for the lesson.
2. Select each line that does not start with #.
3. Press F8 or right-click and select Run or click the icon on the toolbar.
2. Now type the following command to load the start-demo.ps1 script function into the
memory:
. .\start-demo.ps1
Microsoft Confidential
Page 13 of 361
Where <demo_script.txt> is the demo script file for the lesson or exercise.
Note: To exit the demo script at any time you can use the ctrl + c keys.
Microsoft Confidential
Page 14 of 361
Scenario
Welcome to Windows PowerShell.
Windows PowerShell is both a command shell and a scripting language. A significant
difference between PowerShell and other shells is that it is an object-oriented shell. This
aspect of PowerShell will be discussed in detail later.
The use of Windows PowerShell can be divided into two main areas:
Running commands from the command shell interactively
Running scripts
Running scripts will be discussed later. For now, we will discuss running commands in the
shell. Both categories of use of PowerShell are powerful. Depending on the task being
performed will determine which category to use. For example, Exchange 2007 or 2010
administrators will be familiar with running commands in the command shell but they may
not be familiar with running scripts. We will start with opening PowerShell and running
commands in the console.
Microsoft Confidential
Page 15 of 361
You will see that now you have displayed the files and folders that are available from
your current location. Let us compare the PowerShell display and the CMD shell display.
2. Click Start > Run, type cmd and press Enter.
3. In the CMD shell, type the following command:
dir
4. Compare the output of PowerShell and the output of the CMD shell.
You will notice that they are very different. The main advantage of PowerShell is that it
is easy to change the view.
You will see that we now have the same information but it appears very differently. Now
let us open PowerShell from the run box. It will look different.
2. Click Start > Run, type powershell and press Enter.
The PowerShell prompt appears, but this time you will see it looking more like the CMD
shell, as it has the black backgorund and the grey text. Note that it will have the PS
C:\users\administator> prompt.
3. In the PowerShell console, type the following command to display the file system
objects:
dir | format-table name, lastwritetime, length
You will notice that the output is the same as in the blue background window. Now, close
the black background window and let us run another command in the blue background
window.
4. Type the following command to display processes.
get-process
A list of all the processes running on your machine appears. Now, run the same command
from the command prompt.
5. Click Start > Run and type the following command:
powershell –command get-process
Microsoft Confidential
Page 16 of 361
You will see the command run and produce the output, but the window closes as soon as
it finishes running the command. To prevent this, you have the option of keeping the
window open after you run the command. You will do this now using the noexit option.
Note that this needs to be before the –command option.
6. Click Start > Run and type the following command:
PowerShell –noexit –command get-process
You will now see that the command is executed and the window stays open. You can
explore other options for running PowerShell.exe and commands by typing PowerShell /?
Microsoft Confidential
Page 17 of 361
Figure 3
Script Pane
Allows you to create and run scripts. You can open, edit, and run existing scripts in the
Script Pane.
Output Pane
Displays the results of the commands and scripts you have run. You can also copy and
clear the contents in the Output Pane.
Microsoft Confidential
Page 18 of 361
Command Pane
Allows you to type commands. You can run a one-line command or a multi-line
command in the Command Pane. Press SHIFT+ENTER to enter each line of a multiline
command, and press Enter after the last line to execute the mult-line command. The
prompt displayed on top of the Command Pane shows the path to the current working
directory.
From here, we can run PowerShell commands and view the results.
You will now see in the output pane the results of the command. This is just like having a
PowerShell console open, but we are running these commands from within the ISE. Now
will we run some commands from the script pane.
2. Click the Script pane and type the following:
get-process
You can open the file _ISE-commands.ps1 if you do not want to type the commands.
3. On the next line, type the following command:
dir | format-table name, lastwritetime, length
You will notice that the ISE will now color code the different parts of each command.
This is to help identify the different parts of each command such as the command part,
and strings code blocks.
Microsoft Confidential
Page 19 of 361
Microsoft Confidential
Page 20 of 361
Microsoft Confidential
Page 21 of 361
Use of $host.version
1. In the PowerShell console, type the following command to display the version:
$host.version
This will now display the version number of Windows PowerShell. The number to take
the most note of is the major version number.
Use of $psversiontable
1. In the PowerShell console, type the following command to view the ps version table:
$psversiontable
This table of version numbers not only gives you the version of PowerShell installed but
also lists the version of other related components. This is useful when you start looking at
some of the advanced features of PowerShell such as remoting. The number to take
interested in here is the PSVersion number.
Use of Registry
You can also check the version of PowerShell installed on a machine by checking the registry.
This can be very useful, as it will allow us to check the version of PowerShell installed on a
remote machine without having to run commands in a PowerShell console.
1. In the PowerShell console, type the following command to get the version information
from the registry:
get-itemproperty HKLM:\software\microsoft\PowerShell\1\PowerShellEngine
You will now see the information from the registry key. The properties to take note of are
the runtimeversion and the powershellversion number.
You can use the same path on a remote machine to check the PowerShell version
installed on the target. This will be discussed later.
Use of PSSnapins
By looking at the versions of the PowerShell snapins you can determine the version of
PowerShell and see the versions of each snapin that makes up the collections of PowerShell
Cmdlets.
1. In the PowerShell console, type the following command to list the PowerShell snap-ins:
get-pssnapin
You will now see the current PowerShell snapins and their PowerShell version numbers.
Microsoft Confidential
Page 22 of 361
This variable contains the path to the PowerShell install location. Note that even on a
machine with PowerShell v2 installed, this still points
to %systemroot%\ System32\WindowsPowerShell\v1.0.
The registry path for PowerShell v2 is also HKLM:\software\microsoft\PowerShell\1\.
Microsoft Confidential
Page 23 of 361
Transcript commands will not work if you are running the demos from within the ISE
2. In the PowerShell console, type the following command to list the commands available.
get-command
A list of commands available to you under the current PowerShell console appears.
However, you will notice that this list contains different types of commands. For now,
you need only Cmdlets. Use get-command to display only the Cmdlets.
3. In the PowerShell console, type the following command to list Cmdlets:
get-command –commandtype cmdlet
This will now list just the Cmdlets. You will notice it is a much shorter list than before. In
fact you can use PowerShell to tell exactly how many Cmdlets there are. You can do this
easily using two different methods.
4. In the PowerShell console, type the following command to count the Cmdlets available:
get-command –commandtype cmdlet | measure-object
The count of available Cmdlets appears. By default, in Windows 7 the count should be
236 at the time of writing. There is another way to do this.
5. In the PowerShell console, type the following command to count the Cmdlets available:
(get-command –commandtype cmdlet).count
The number of Cmdlets appears. However, this time you will see only the number.
Now let us run some more commands.
1. In the PowerShell console, type the following command to get the current date:
get-date
The current date and time appears. You can change what appears by using some
parameters in the command.
Microsoft Confidential
Page 24 of 361
2. In the PowerShell console, type the following command to get just the date:
get-date –displayhint date
2. In the PowerShell console, type the following command to display the long date format:
get-date –displayhint time –format D
3. In the PowerShell console, type the following to display the short time format:
get-date –displayhint time –format t
4. In the PowerShell console, type the following command to display the long time format:
get-date –displayhint time –format T
5. In the PowerShell console, type the following to display the date in a given format:
get-date –displayhint time –format yyyy/MM/dd
This will display the date in the given format. Note that this is case sensitive. Note also
that you should always use ISO8601 for dates rather than a specific locale.
6. In the PowerShell console, type the following command to display time in a given
format:
get-date –displayhint time –format hh:mm:ss
This will display the time in the given format. Again, note that this is case sensitive and
the lower-case ‘mm’ produces minutes, whereas the upper-case ‘MM’ produces the
month.
Let us look at something more interesting.
1. In the PowerShell console, type the following command to list the current processes:
get-process
A list of the currently running processes appears. We can do the same with services.
2. In the PowerShell console, type the following command to list the services on the system:
get-service
A list of services and their statuses appears. However, you might be interested in only
one service. You can view this by typing its name after get-service.
Microsoft Confidential
Page 25 of 361
3. In the PowerShell console, type the following command to get information for just the
bits service:
get-service bits
Now you will see information about only the bits service
4. In the PowerShell console, type the following command to generate a random number
between 1 and 10:
Get-random –Minimum 1 –Maximum 10
Microsoft Confidential
Page 26 of 361
You will now see that you have the same output that you would have had if you run the
command in the CMD shell.
2. In the PowerShell console, type the following command to get all IP configuration
information:
ipconfig /all
This will now list a summary of the system information of the current machine.
What may be useful is to write this information to a file. Just like the CMD shell, you can
use the > and >> symbols to redirect the output. > will overwrite the output, whereas >>
will append the output.
4. In the PowerShell console, type the following command to redirect output to a file:
systeminfo >systeminfo.txt
This will now write that information to a text file for us. To view it lets use notepad
5. In the PowerShell console, type the following command to open the text file in notepad:
notepad systeminfo.txt
You will now see the information from the command in the text file. This not only works
for external commands, but also for Cmdlets.
6. In the PowerShell console, type the following command to redirect the Cmdlet output to
a file:
get-service > services.txt
7. In the PowerShell console, type the following command to read the file:
notepad services.txt
Microsoft Confidential
Page 27 of 361
is especially useful if you have a command that takes a while to run and you do not want to
wait until it is finished. To do this, use the semicolon character. This is the statement
terminator for PowerShell.
1. In the PowerShell console, type the following command to run multiple commands, add
multiple items to a text file and open it in Notepad:
ipconfig /all > systemconfig.txt; systeminfo >>systemconfig.txt ; get-service
>>systemconfig.txt; notepad systemconfig.txt
The three commands to get information about the system will now run, and each of these
will put information into the systemconfig.txt. Finally, open Notepad to view this
information.
The $lastexitcode variable can be very useful when working with external commands. This
variable contains the exit code or errorlevel value from the external command. In general, an
exit code of zero is a success and anything non-zero is considered an error of some type.
However, this may not be true depending on the program you are running. Let us look at a
simple example using the ping command.
1. In the PowerShell console, type the following command to ping the local machine:
ping localhost
2. In the PowerShell console, type the following command to check the status of the
previous command:
$lastexitcode
You will now see that the value of the $lastexitcode is now zero. This is because we were
able to ping the localhost.
3. In the PowerShell console, type the following command to ping a non-existing host:
ping fakeserver
4. In the PowerShell console, type the following command to check the status of the
previous command:
$lastexitcode
You will now see that the value of the $lastexitcode is now one. This is because, you
were unable to ping the fakeserver host, as it does not exist.
Microsoft Confidential
Page 28 of 361
You will now see a list of Cmdlets, functions and alias. This does work a little differently
in PowerShell v1 and v2. In v1 you would have only seen Cmdlets by default.
2. In the PowerShell console, type the following command to list just Cmdlets:
get-command –commandtype cmdlet
A list of commands that start with get appears. You will notice that most of these are
Cmdlets. However, there are some external commands such as getmac.exe and
gettingstarted.exe listed. This is because, these are commands that PowerShell can run.
You will notice that these external commands are listed as the type of application. This
tells you that it is an external command. If you combine the last two options, -
commandtype and get* you will see only the Cmdlets.
4. In the PowerShell console, type the following command to list just Cmdlets that start
with get:
get-command –commandtype cmdlet get*
Now, you will see just Cmdlets that start with get. There is an easier way to do this.
You can use the -verb option to look for Cmdlets or functions.
5. In the PowerShell console, type the following command to list Cmdlets with the verb get:
get-command –verb get
You will now see any Cmdlets and functions that have the verb get in their name. We
will go into more details about the naming of Cmdlets later, but you will find that the
names of the Cmdlets follow verb-noun in their names. This makes it easy to know what
a Cmdlet might do, but also makes is easy to find the Cmdlets.
Microsoft Confidential
Page 29 of 361
6. In the PowerShell console, type the following command to list Cmdlets with the noun
service:
get-command –noun service
7. You will now see all the Cmdlets that are related to services. We can also do this with a
wildcard search.
8. In the PowerShell console, type the following command to get all commands that end
with service:
get-command *service
Microsoft Confidential
Page 30 of 361
The help information for the get-help Cmdlet appears. You will notice that information
follows a particular format. The good thing is that this format is the same for all Cmdlets.
2. In the PowerShell console, type the following command to get help on the get-command
Cmdlet:
get-help get-command
The help information for the get-command Cmdlet appears. You can expand on this by
using two options.
3. In the PowerShell console, type the following command to get a detailed help on get-
command:
get-help get-command –detailed
Some of the same information as before appears on top of the display. However, as you
scroll down you will find more information such as the parameter descriptions and some
examples. Let us do this again with a different Cmdlet.
4. In the PowerShell console, type the following to get detailed help on get-service Cmdlet:
get-help get-service –detailed
The detailed help information for the get-service Cmdlet appears. There is another option
that is useful, the –full option. This will display all the help information for the Cmdlet.
5. In the PowerShell console, type the following to get all help on get-service Cmdlet:
get-help get-service –full
In addition to getting help on Cmdlets, there are many other help topics available. To see
them we will use the following command.
Microsoft Confidential
Page 31 of 361
7. In the PowerShell console, type the following command to list all help topics:
get-help *
The full list of help topics available appears. You will see the alias, the functions,
Cmdlets and finally the helpfile topics. You will notice that all the helpfile topics all have
the name about_ this allows us to look just at them.
8. In the PowerShell console, type the following command to list just the about topics:
get-help about
The information about PowerShell wildcards appears. Note that there is no –full or –
detailed option with the about topics.
Microsoft Confidential
Page 32 of 361
The previous commands run up to a default maximum of 64 commands. You will notice
that each command has an ID associated with it. This ID can be used to re-run a
particular command.
2. In the list of commands, locate the ID for the get-help and get-service commands.
3. In the PowerShell console, type the following command to invoke the command from
history:
invoke-history –id <that ID from above>
The command executes again. This can be useful when you have complicated lines of
code and you do not want to use the up arrow to go through all commands again.
The previous commands can also be exported and later imported to use again.
1. In the PowerShell console, type the following command to export the history to a csv file:
get-history | export-csv myhistory.csv
As this is a new PowerShell session, you will see that there currently are no commands in
the history. You can now import the commands from the CSV file we created to include
some history commands that can be invoked.
3. In the new PowerShell console, type the following command to import the history from
the other session:
import-csv myhistory.csv | add-history
4. In the new PowerShell console, type the following command to view the current history:
get-history
You will now see that there are commands loaded into the history and can be invoked.
Notice that the IDs will not be the same as the session that we exported the information
from.
Microsoft Confidential
Page 33 of 361
One thing to note is that by default, you will only see the last 64 commands. This number
is defined by the variable $MaximumHistoryCount.
To increase the maximum commands:
1. In the original PowerShell console, type the following command to increase the
maximum command history count:
$MaximumHistoryCount = 100
This will allow you to look at up to 100 previous commands. You can also specify –
count 100 for get history to display the 100 commands. By default, you will only get 32
displayed.
2. In the PowerShell console, type the following command to get the last 100 commands:
get-history –count 100
There is another way of viewing the previous commands run. However, this will also
show the output produced from each of these.
If you remember, earlier in the lesson, we created a transcript. This will have recorded all the
previous commands that we have run. So let us stop and view the contents of that transcript.
1. In the PowerShell console, type the following command to stop the transcript:
Stop-Transcript
This will stop recording of the session and tell you where the output file is.
Again, remember here (and moving forward through the additional demonstrations) that
transcript commands will fail if being run through the ISE.
By reading the file, you will see the history of all the commands you have run. This file
should be kept for later use, as it can be useful to look at the commands you have run.
It is suggested that at least for the next few lessons, start a transcript for each lesson so that
you can review those later.
In addition to the history Cmdlets, you can also use the up arrow to see the previous
commands run. To run the same command again, press Enter. You can also use the up arrow
to bring up a previous command and modify it. The drawback here is that if you need to go
back several commands, or you need to re-run multiple commands, the order of these
commands will change each time a new command is executed.
Microsoft Confidential
Page 34 of 361
Prerequisites
The lab requires a Windows 7 client running in a domain environment.
Microsoft Confidential
Page 35 of 361
Note: This global variable will be lost when the PowerShell session is terminated. The
variable assignment can be added to a Profile if it is required to persist between
sessions.
Note also that you should always use ISO8601 for dates rather than a specific locale
as shown in tostring("yyyyMMddHHmmss")) above.
3. Type the following to start the recording part of this PowerShell session in a text file.
start-transcript.
Microsoft Confidential
Page 36 of 361
stop-transcript
Note that the file path and name appears on the console.
6. Type the following to view the transcript file name.
notepad $transcript
Note that the file path and name appears on the console.
10. Type the following to view the transcript file name.
notepad $transcript
Note that the same file is used and the previous content was overwritten.
11. Type the following to start recording again
start-transcript -append
Note that the file path and name appears on the console.
14. Type the following to view the transcript file name.
notepad $transcript
Note that the same file is used and the previous content is still available.
Microsoft Confidential
Page 37 of 361
4. Type the following to return the methods and properties that are available for the output
of the (get-help get-command) command.
(get-help get-command) | get-member
5. Type the following to return only the properties that are available for the output of the
(get-help get-command) command.
(get-help get-command) | get-member -membertype noteproperty
6. Type the following to return only the methods that are available for the output of the (get-
help get-command) command.
(get-help get-command) | get-member -membertype method
9. Type the following to view the static members of the datetime type.
[datetime] | get-member -static
Microsoft Confidential
Page 38 of 361
Microsoft Confidential
Page 39 of 361
Microsoft Confidential
Page 40 of 361
Microsoft Confidential
Page 41 of 361
Objectives
After completing this lab, you will be able to:
Explore command discovery, syntax and usage
Leverage command help topics
Discover & create command aliases
Explain the usage of classes, objects & various object models in PowerShell
Pre-requisites
To complete this lab, you need:
A Windows 7 workstation logged onto with administrator credentials
Microsoft Confidential
Page 42 of 361
Scenario
PowerShell consists of four types of commands:
Cmdlets
Functions
Scripts
External commands
In this exercise, we will focus on using the first type of commands, known as Cmdlets
(pronounced ‘command-lets’).
Cmdlets are commands ‘built-in’ to PowerShell. They are written in a .NET language (C#,
VB.NET, F#, etc.) and compiled into a dynamic link library (.DLL) file.
236 Cmdlets are available by default in PowerShell v2.0 and cover a wide range of uses, from
interacting with the file system to listing event log and service information.
Although out-of-scope for this lesson, it is worth noting that new Cmdlets authored and
compiled by a developer can be loaded into the PowerShell process, alongside the default
Cmdlets.
Microsoft Confidential
Page 43 of 361
This command will return a list of all processes running on the local machine.
2. To limit the number of processes returned, add a parameter and an argument. The
following example uses the Get-Process Cmdlet’s –Name parameter.
Get-Process -Name explorer
This will return a single line of information about the “explorer” process running on the
local machine.
3. Parameter names can also be shortened by abbreviating them to a unique value.
Get-Process -Na explorer
4. Next, try typing the same command using PowerShell’s tab-completion feature. Type the
following:
Get-
Then, press the Tab key until the full command name appears. Pressing SHIFT+TAB
moves backwards through the list.
5. This feature also works with parameter names. Type a space character and a hyphen
character. Pressing the Tab key will cycle through all the parameters for a particular
command. Again, pressing Shift+Tab moves backwards through the list.
Get-Process -<press tab key>
6. Certain parameter names can be omitted entirely with the command still working as
expected. Below, the argument explorer is associated with the –Name parameter by its
position in the command. Remember that the arguments have to be passed in the default
order specified by the Cmdlet.
Get-Process explorer
7. Many parameters also accept a list of arguments, allowing more than one value to be
bound to a parameter. In PowerShell, lists can be specified by separating each item with a
comma.
Get-Process –Name explorer,system,wmiprvse
8. Now add a parameter that does not require an argument. Such parameters are called
switch parameters, since they change the command's behavior by enabling a feature
within it.
Microsoft Confidential
Page 44 of 361
For example, the module switch parameter of the Get-Process Cmdlet turns on a feature
that lists all the .dll files loaded by the returned process.
Get-Process -Name explorer -Module
9. If you omit any required parameters, PowerShell will prompt you to supply the required
arguments automatically. In the example below, you are prompted for the -Path and -
Type parameter arguments to successfully create a new folder on the local C: volume.
PS C:\Users\Administrator> New-Item
Directory: C:\
A list of Cmdlets, Functions and Aliases will be displayed, since all command types are
listed by default.
3. If you were searching for a command containing a particular string you can enclose it in
wildcard (*) characters.
Get-Command *item*
4. Get-Command also has –verb and –noun parameters which allow you to limit the search
to commands matching the verb and/or noun part of the name. Below we list all the
Cmdlets where the word on the left-hand side of the hyphen, the verb, matches the string
“get”.
Get-Command –verb get
Microsoft Confidential
Page 45 of 361
6. List all commands where the verb part of the name ends with the letter ‘w’.
Get-Command –verb *w
This use of the command displays basic help information. Get-Help also has a number of
switch parameters that control the amount of help information returned. The -full
parameter returns all information about a particular command.
Get-Help Get-Service -full
The -examples parameter lists different ways in which a command can be used.
Get-Help New-Item -examples
The -detailed parameter adds examples and descriptions to the basic help.
Get-Help New-Item -detailed
As with all commands, wildcard characters can be used to return help for multiple
matches. If only one command matches, PowerShell returns the help for that command. If
not, a list of matching help topics is displayed.
Get-Help new*
Another useful switch parameter for this Cmdlet is -Online. If you have internet access,
this parameter will open the TechNet Windows PowerShell command Help Topics
documentation for the specified command. http://technet.microsoft.com/en-
us/library/dd347701.aspx.
Get-Help New-Item -Online
2. Get-Help can also be used to display conceptual help about the PowerShell Language.
This is accessed by using the argument about_*, which will list all of the conceptual help
topics.
Get-Help about_*
You can then choose the topic and use its full name to list the entire help file.
Get-Help about_Command_Syntax
Microsoft Confidential
Page 46 of 361
Note: A very useful piece of information returned by all the Get-Help switch parameters
is the command syntax. This has a special format that is easy to understand, once you
know how to interpret it!
Microsoft Confidential
Page 47 of 361
Convenience aliases: Convenience aliases are, as the name suggests, for convenience. For
example, Get-ChildItem has a convenience alias of gci, which saves the time required to type
the complete command name.
gci
Note: By default, PowerShell 2.0 has 137 aliases. The majority can be re-assigned to
point to a different command or deleted entirely, although they will be re-populated
when a new console or ISE session is established.
You will see five Cmdlets that can be used to manipulate aliases. The most useful of
which are Get-Alias, New-Alias and Set-Alias.
a. The Get-Alias Cmdlet is used to list all aliases.
Get-Alias
b. New-Alias allows you to create new aliases for a Cmdlet, Function or executable file.
The -Name parameter argument specifies the name of the new alias and the -Value
parameter specifies the command to alias.
New-Alias –Name gp –Value Get-Process
Microsoft Confidential
Page 48 of 361
Microsoft Confidential
Page 49 of 361
What is an Object?
Objects are all around us. A car is an object with a collection of separate parts, such as a
steering wheel, accelerator pedal and brakes. To drive the car, we can use the parts to steer,
accelerate and slow/stop the vehicle. We can now divide the car (object) into two distinct
concepts.
A collection of parts
Uses of the parts to change the car’s behavior
Now, apply this object model to the Windows Operating System.
A Windows Service object has a collection of parts called Properties. Properties represent
the state of a service, such as the service name and status. The service status can be changed
by using object Methods. Object Methods allow you to start or stop a service. Collectively,
properties and methods are called object Members.
Members
Properties Methods
Note: Method names can be easily distinguished from property names as they are
always appended with a pair of smooth brackets ‘()’.
Microsoft Confidential
Page 50 of 361
2. Alternatively, you can choose not to use the pipeline and employ the Get-Member
Cmdlet’s InputObject parameter. This command however lists the members of the
collectin of pipeline data as a whole, rather than the individual items in the collection.
Get-Member –InputObject (Get-Service)
The top of the output lists the type name of the object(s). In the first case when piping to
Ger-Member, you can see it is a System.ServiceProcess.ServiceController type of object.
TypeName: System.ServiceProcess.ServiceController
The next piece of information displayed is the collection of members (properties and
methods). The output below displays three columns of member information: the name,
membertype and definition.
Name MemberType Definition
---- ---------- ----------
Name AliasProperty Name = ServiceName
RequiredServices AliasProperty RequiredServices = ServicesDependedOn
Disposed Event System.EventHandler Disposed(System.Object,
Close Method System.Void Close()
Continue Method System.Void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef
Dispose Method System.Void Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method System.Void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Pause Method System.Void Pause()
Refresh Method System.Void Refresh()
Start Method System.Void Start(), System.Void
Stop Method System.Void Stop()
ToString Method string ToString()
WaitForStatus Method System.Void
CanPauseAndContinue Property System.Boolean CanPauseAndContinue {get;}
CanShutdown Property System.Boolean CanShutdown {get;}
CanStop Property System.Boolean CanStop {get;}
Container Property System.ComponentModel.IContainer Container
Microsoft Confidential
Page 51 of 361
Note: Pipeline operations will be covered in more detail in the next lesson).
Count : 32
Average :
Sum :
Maximum :
Minimum :
Property : MemberType
4. It is possible to shorten the output from this Cmdlet by listing only the properties.
Get-Service | Get-Member –MemberType property
6. Now that you have uncovered the object’s members, you can use them to access state
information using properties and manipulate the object using methods.
2. Type the variable name to confirm that you have referenced the correct service.
By default, three properties of the service object are displayed: Status, Name and
DisplayName.
Microsoft Confidential
Page 52 of 361
$ALGService
3. Type a dot (.) character directly after the variable name and repeatedly press the Tab key.
The member names for this object type will be displayed one after the other.
4. Press Enter to display the information stored in one of the properties.
$ALGService.DisplayName
Application Layer Gateway Service
5. Type the variable name again, followed by a dot, and type Start(). Press Enter.
Note: Be sure to append smooth brackets ‘()’ after the method name.
$ALGService.Start()
9. Let’s see another example of accessing object members. Assign a string to a variable and
pass it through the pipeline to Get-Member to discover the string object’s members.
Alternatively, you can use the alias for Get-Member (gm).
$strMyName = “My name is Chris”
$strMyName | Get-Member
10. You can also just pipe the string directly to the Get-Member Cmdlet. Both commands in
steps 8 and 9 produce the same output.
“My name is Chris” | Get-Member
11. The object type name returned is System.String. This type has 2 properties and 32
methods. The length property stores the number of characters in the string. In this case,
the string consists of 16 characters.
$strMyName.length
16
Microsoft Confidential
Page 53 of 361
Alternatively, call the property using the string, rather than the variable. Again, both
commands produce identical output.
(“My name is Chris”).length
16
Note: Even though the parenthesis are not required above, it makes sense to have
them since it applies to other types of commands where this is not possible without
parenthesis.
o The Substring() method returns a part of the string. This method requires input
parameters to be provided within the parenthesis to represent the startIndex.
$strMyName.Substring(11)
Chris
Note: The $strMyName variable is never modified by any of the methods and still
contains the original string.
Microsoft Confidential
Page 54 of 361
2. Use the Sort-Object Cmdlet to sort a list of file and folders by their lastwritetime
property.
Get-ChildItem –Path C:\Windows | Sort-Object –Property LastWriteTime
3. Find Process objects with more than 500 open handles using the Where-Object Cmdlet.
Get-Process | Where-Object {$_.handles –gt 500}
2. Confirm that the Process objects’ Threads property contains a list of thread objects.
$process.Threads
Since the Threads property is an array object, it has a count property that stores the
number of thread objects contained within it.
3. Use the Add-Member Cmdlet to add a new scriptproperty called ThreadCount to the
process object. Note that the InputObject parameter is used to supply the object Add-
Member operates on.
The Value property argument is contained in a set of curly brackets '{}'. This is called a
scriptblock and can contain any PowerShell code. The $this variable refers to the current
object instance stored in the $process variable.
Add-Member –InputObject $process -MemberType scriptproperty -Name ThreadCount `
–Value {$this.Threads.Count} -PassThru
Microsoft Confidential
Page 55 of 361
4. Access the new property to display the number of threads running in this particular
process.
$process.ThreadCount
15
Microsoft Confidential
Page 56 of 361
Namespace
System.String
Type
Namespace
System.DirectoryServices.DirectoryEntry
Type
Note: Types are also called classes. You will probably see the two names used
interchangeably.
Microsoft Confidential
Page 57 of 361
2. Use the GetType() method, which is included on every .NET object by default, to
discover the type of object PowerShell created.
PS C:\ > $strHello.GetType()
3. We can view the fully qualified name of the type by accessing the FullName property of
the type object.
$strHello.GetType().Fullname
System.String
4. You can use the New-Object Cmdlet to create a new instance of a type. In the next
example, you will create a new System.String object using this method, although it
produces exactly the same result as variable assignment shown above.
$strHello2 = New-Object –TypeName System.String(“Hello World”)
5. New-Object allows us to create any object in the .NET framework. For example, creating
a directory searcher allows us to query Active Directory
Create a System.Directoryservices.Directorysearcher object
$objsearcher = new-object system.directoryservices.directorysearcher
6. Execute the findone method to find the first object in Active Directory using a filter of *
$objsearcher.findone()
Microsoft Confidential
Page 58 of 361
8. Use the objects Send() method to send a ping to a specific hostname or IP address.
$ping.Send(“localhost”)
Object Models
The .NET framework is not the only object model PowerShell can use.
The Component Object Model (COM) and Windows Management Instrumentation (WMI)
technologies are also directly supported.
2. To list the members of the new COM object, simply pipe the variable to Get-Member.
$objWSH | Get-Member
Typename: System.__ComObject#{41904400-be18-11d3-a28b-00104bd35090}
Note: In practice the popup method of the WSH object should not be used. Instead
the .Net framework type of system.windows.forms.messagebox should be used.
Microsoft Confidential
Page 59 of 361
2. Type one of the class names as the argument to the -class parameter to list its information.
Store the object in a variable.
$objBIOS = Get-WMIObject –namespace root\CIMv2 –class Win32_BIOS
3. List the member information (properties and methods) for your chosen class using Get-
Member.
$objBIOS | Get-Member
Many WMI objects allow changing the object’s state through object methods. The
Win32_OperatingSystem class allows us to reboot the OS locally or remotely.
Note: On Windows Vista and above Operating Systems, the PowerShell console must
be run as an administrator and the shutdown privilege enabled.
Microsoft Confidential
Page 60 of 361
Prerequisites
The lab requires a windows 7 client running in a domain environment.
Microsoft Confidential
Page 61 of 361
Scenario
As we have seen, PowerShell contains a large number of built-in commands, called cmdlets. In this
exercise we will find cmdlets and discover their syntax in order to complete a task.
On the windows task bar locate the icon. Click on this icon.
The PowerShell window will open.
Microsoft Confidential
Page 62 of 361
Tasks to Perform:
The objective of this exercise is to measure the total size of all .txt files in C:\Program Files
and all its subfolders.
1. From the PowerShell console, execute the following command. In PowerShell v2.0, the –
commandType parameter is required to include only cmdlet objects in the output. By
default this command returns cmdlets, functions and aliases.
Get-Command –commandType cmdlet
This will return a list of the default PowerShell cmdlets. While this list is comprehensive, it is
also rather large.
2. Let’s reduce the size of the list by using one of the Get-Command cmdlets parameters to
filter the results. To do this we must first discover how to use Get-Command, by
employing the Get-Help cmdlet, to view the associated help file.
Get-Help –name Get-Command
As you can see, the output is fairly general. It may be more help to only list the parameters
available on this cmdlet.
3. Modify the previous command to include –Parameter, followed by a wildcard (*)
character, to list all the parameters for the cmdlet.
Get-Help –Name Get-Command –Parameter *
4. The output gives much more detail about each parameter. As our first objective is to find
the cmdlets we need to complete the task, use the –Name, -Verb and –Noun parameters
to search for cmdlets by full name, verb and noun. Specifying keywords and wildcard
characters will allow Get-Command to filter the cmdlet list.
The task states that we must ‘measure the total size of files in a folder and its subfolders’. To
complete the objective, we must first get a list of file & folder objects. The Get-* cmdlets are
often used as the first cmdlet in a PowerShell pipeline, as they return a list of objects of a
specific type.
Get-Command -commandType cmdlet get*
5. The list is much shorter than the output of step 1. The cmdlet we require is Get-ChildItem,
near the top of the list. Familiarize yourself with this cmdlet’s parameters and syntax
using Get-Help.
Get-Help –Name Get-Childitem –Parameter *
Another great way to discover cmdlet syntax and usage is by using Get-Help’s –Example
switch parameter.
Get-Help –Name Get-ChildItem –Example
6. Use the help to decide which parameters are needed to list all text files beneath the path
C:\Program Files. Note that the path (C:\Program Files) contains a space character, so it
must be enclosed within single or double quotes.
Microsoft Confidential
Page 63 of 361
7. The command does return all .txt files and folders beneath the specified path. The –
recurse switch parameter (a parameter that doesn’t require an argument), ensures that all
subfolders are searched & the –Filter parameter’s argument constrains the search to files
with the extension ‘txt’.
8. The previous steps complete the collection of file and folder objects. Next, we need to
calculate their total size. To do this we require a cmdlet that can measure the length
property of all file objects returned (folders do not have a length property & therefore
don’t directly have an impact on disk space, other than their entries in the Master File
Table).
Use Get-Command to search for cmdlets with the keyword ‘Measure’. Note that this time
we aren’t sure if the noun or verb part of the cmdlet name contains the text, so we use the
–name parameter to search the full name. Surrounding the text with wild-card characters
ensures all possible matches are returned.
Get-Command –CommandType cmdlet –Name *Measure*
9. Fortunately only 2 cmdlets contain the word ‘measure’. To decide which one to use, have
a look at their associated help files. Instead of using the Get-Help cmdlet, try using the
shortcut to displaying the default help for a cmdlet, the -? Switch parameter.
Measure-Object -?
10. The Measure-Object cmdlet is suitable to complete this task as it ‘…calculates the
numeric properties of objects…’ Use Get-Help’s –Detailed, -Example and –Parameter
parameters to discover more information about the commands syntax & usage.
Get-Help Measure-Object –Detailed
Get-Help Measure-Object –Example
Get-Help Measure-Object –Parameter *
Measure-Object accepts pipeline object input and allows the property of interest to be
specified using its –Property parameter. The –sum switch parameter stores a running total
of the file sizes.
Get-service | Measure-Object
11. The ‘length’ property of a file object stores its size on disk, in bytes. A simple pipeline
operation (pipelines are covered in detail in the next module) is all that is needed to pass
the filtered list of .txt files to Measure-Object.
Get-ChildItem –path ‘C:\Program Files’ –Filter *.txt –Recurse |
Measure-Object –Property length –Sum
12. The Measure-Object cmdlet returns a single object containing its results, therefore we are
able to access its ‘Sum’ property directly and perform further formatting. Such as
displaying the total file size in Megabytes.
To do this, enclose the previous pipeline command in smooth parentheses and use a dot ‘.’
to access the object’s ‘Sum’ property.
Microsoft Confidential
Page 64 of 361
Finally, use the division operator (/) and ‘MB’ constant to convert the ‘Sum’ property’s
byte result to Megabytes.
(Get-ChildItem –path ‘C:\Program Files’ –Filter *.txt –Recurse |
Measure-Object –Property length –Sum).sum / 1MB
Microsoft Confidential
Page 65 of 361
Scenario
In this exercise we will learn how to discover the members of existing objects and create new .NET
object instances.
On the windows task bar locate the icon. Click on this icon.
The PowerShell window will open.
Microsoft Confidential
Page 66 of 361
Tasks to Perform:
Since everything we will work with in PowerShell is an object, it is crucial to be able to
discover the various members (properties and methods) of any object.
We will take the common administrative task of working with files and folders as an example
of how to discover and use object members.
1. Use the Get-ChildItem cmdlet to list file and folder objects from C:\Windows and
pipeline them to the Get-Member cmdlet in order to view the type of objects returned.
Get-ChildItem –path C:\Windows | get-Member
2. From the output we can see that two different types of object exist in the file system,
System.IO.DirectoryInfo and System.IO.FileInfo objects.
Each of these object types contain a large number of members. Execute the command
above, but this time, include Get-Member’s –MemberType parameter & specify the
argument ‘property’. The output now only lists the object properties.
Get-ChildItem –Path C:\Windows | Get-Member –MemberType property
3. The LastWriteTime property can be seen in the listing. This property contains a date
object that stores the last time the file or folder was modified.
4. How would you list only object methods?
5. Next, we will create a pipeline command to filter all files and folders modified over 60
days ago. To do this we will need to create an object that represents a date. Use the Get-
Date cmdlet to create a new date object and save a reference to this object in a variable.
$Date = Get-Date
6. Using the Get-Member cmdlet we can view the members of the date object referenced by
the $Date variable.
$Date | Get-Member
7. One member that can be seen in the output is the AddDays() method. By supplying an
input parameter to the method we can produce a modified date.
$Date.AddDays(-60)
8. We can now use the members found on the file, folder and date objects to perform a
pipeline operation to determine the files and folders modified over 60 days previously.
Microsoft Confidential
Page 67 of 361
Microsoft Confidential
Page 68 of 361
On the windows task bar locate the icon. Click on this icon.
The PowerShell window will open.
Microsoft Confidential
Page 69 of 361
Tasks to perform:
In this exercise we will create a new TcpClient object and use it to check connectivity to a
TCP port number on a remote machine.
1. First we must create an instance of the TcpClient class and save a reference to it in a
variable. To do this, specify the .NET class name of the object as an argument to the
New-Object cmdlet’s TypeName property.
The full name of the class is System.Net.Sockets.TcpClient.
$tcpClient = New-Object –TypeName System.Net.Sockets.TcpClient
3. One of the members listed is the Connect() method. An easy way to view the input
parameters for a method is to type the method name omitting the parentheses.
$tcpClient.Connect
Four different numbers and combinations of input parameters can be specified for this
particular method – This method is referred to as having four ‘overloads’.
The overload we are going to use (the first in the above list) requires two objects, a string
that represents the hostname of the remote machine and an Integer that stores the port
name on which we wish to connect.
5. If no error was returned, confirm that the connection is open using the connected property.
The value ‘True’ should be returned
$tcpClient.Connected
6. Use the Close() method to close the TCP socket connection and dispose of the TCPClient
object.
$tcpClient.Close()
In the next exercise we will create a COM object. Thousands of COM objects ‘ProgID’
identifiers are listed in the Operating System registry under HKEY_CLASSES_ROOT.
We will create an instance of the InternetExplorer.Application COM class, which allows
Microsoft’s Internet Explorer browser to be manipulated programmatically.
Note: The next task requires internet access, and should therefore be performed on
the student host machine.
Microsoft Confidential
Page 70 of 361
1. Creating a COM object instance is also achieved using the New-Object cmdlet, although
the –ComObject parameter is used, instead of the –TypeName parameter.
$ie = New-Object –ComObject InternetExplorer.Application
2. Get-Member can be used to view the object’s members in exactly the same manner
as .NET objects.
$ie | Get-Member
3. The Navigate2() method opens the URL specified in the method’s input parameter.
$ie.Navigate2(“http://www.microsoft.com”)
4. At this point, the Internet Explorer window is not visible. Using Get-Member, locate the
member name that allows the window to appear. What data type does it accept?
5. Next, set the Visible property to the value $true.
$ie.Visible = $true
6. The Internet Explorer should now be visible. How would you close the Internet Explorer
window using PowerShell?
Microsoft Confidential
Page 71 of 361
Microsoft Confidential
Page 72 of 361
Objectives
After completing this lab, you will be able to:
Understand the fundamental operators
Understand pipeline usage, syntax, and the pipeline variable
Display, Filter, Sort, and Group Cmdlet output via the pipeline
Control pipeline input and output
Prerequisites
To complete this lab, you need:
A Windows 7 workstation logged onto with administrator credentials
Microsoft Confidential
Page 73 of 361
Scenario
PowerShell consists of many different operators:
Arithmetic
Assignment
Comparison
Logical
Redirection
Substring
Type
Unary
Special
In this lesson, you will understand comparison and logical operators, which you will
commonly encounter while working with the pipeline.
Comparison operators are used to:
Compare values such as text and numbers
Provide a mechanism for testing conditions such as during a call to the Where-Object
Cmdlet
There are 13 different comparison operators. Some test for simple equality while others work
with sets or special matching situations.
Logical operators allow you to join multiple operations to check for compound conditions
being true or false. There are five logical operators you will work with, two of which serve
the same purpose.
Log on to VM Environment
Log on to the Windows 7 Enterprise client
Microsoft Confidential
Page 74 of 361
1. Open the PowerShell console or ISE and type the following command:
“PowerShell” –eq “powershell”
This command will return a value of True indicating that these two string values are
equal to each other.
2. You can also test if two values are not equal by running the following command:
“POWERSHELL” –ne “powershell”
This will return a value of False since the strings have different casing. This will work
with any comparison operator, not just –eq and –ne.
4. PowerShell can be made to explicitly do a case-insensitive comparison, which can help
readability in scripts in certain cases. This is done by using an i instead of a c.
“PowerShell” –ieq “powershell”
This will return True once again since an insensitive comparison was explicitly used.
5. Testing equality does not stop with -eq and -ne. You may also need to know whether
something is less than, greater than, and so on. When working with numbers, these
operations function exactly as you would expect; the following commands:
4 –gt 4
3 –ge 3
3 –lt 7
7 –le 4
The commands above will return the values False, True, True, False, respectively, for
tests of greater than, greater than or equal to, less than, and less than or equal to
operators.
6. You can do the same thing with strings as well.
“Reed” –gt “Read”
“k” –lt “g”
“powershell” –le “POWERSHELL”
“user” –cge “USER”
These commands will return the values True, False, True, and False, respectively. When
comparing string values, PowerShell uses the Compare method built into the String type.
Therefore, in a case-sensitive comparison, “u” is considered less than “U”.
7. It is interesting to note that you can use arrays when testing for equality. When you do
this, you will get more than a simple True or False return value.
Microsoft Confidential
Page 75 of 361
This will then return False for the first command and True for the second.
Microsoft Confidential
Page 76 of 361
These three commands will return true, false, and true, respectively.
Logical Operators
In order to combine a number of different comparison operators, you need to use logical
operators to make compound statements. The logical operators you can use are -and, -or, -xor,
and -not. There is one additional operator that is available that does the same thing as the -not
operator, but it is only a single character "!" (exclamation mark).
The -and, -or, and -xor operators are binary operators. This means that they operate on two
statements, allow you to combine them, and get a single statement output. Each operator has
a left and a right side statement which are joined, and either side can also be another logical
statement.
The following truth table shows the logical functionality of each operator, where p represents
the statement on the left side of the operator and q represents the statement on the right side:
p q -and -or -xor
$true $true $true $true $false
$true $false $false $true $true
$false $true $false $true $true
$false $false $false $false $false
The -not and ! operators are simpler because they are unary operators − they only operate on
a single statement. So, instead of having a left and right side, you place the operator in front
of the statement you wish to negate.
Microsoft Confidential
Page 77 of 361
p -not !
$true $false $false
$false $true $true
Using these operators within PowerShell is quite simple. However, the order of operations is
a point to take note of, since the incorrect order can cause unexpected results. You can use
parenthesis to override the order of operations, forcing PowerShell to evaluate anything
within the parenthesis first.
(4 –ge 8) –and (5 –lt 10)
! (4 –eq 4)
-not $true –xor $false
-not ($true –xor $false)
Note: The about_Operator_Precedence help topic is not included with PowerShell 2.0
documentation however, it can be read via TechNet http://technet.microsoft.com/en-
us/library/ee681734.aspx
Microsoft Confidential
Page 78 of 361
Scenario
The pipeline allows a user to take a number of simple commands and string them together
into a single pipeline. In the previous exercises, you were writing statements for PowerShell
to evaluate. The evaluation of these statements produced an output.
The fact that these commands produce output without having to explicitly tell PowerShell to
do so ties in directly with the concept of the pipeline.
PowerShell will take an object on the pipeline and pass it from one command to the next until
there are no additional commands to pass through. When an object reaches the end of the
pipeline, PowerShell outputs it to the host.
Log on to VM Environment
Log on to the Windows 7 Enterprise client.
The command above is a single pipeline made up of four commands that take the output
of the Get-Process command and pass it along the pipeline. Each command is separated
by a pipe “|” which sends the output from one command to the next.
2. One of the revolutionary aspects of PowerShell is that the pipeline passes objects rather
than the simple text data you see on the screen.
Get-Process
This command will output the list of running processes on the user's machine with eight
properties displayed for each process, including its ID and working set.
3. Now, take that data and pipe it into Format-Table to display other properties.
Get-Process | Format-Table ID, ProcessName, StartTime, MainWindowTitle -Autosize
Even though Get-Process by itself only displays six properties for each process, there is
more data that gets passed along the pipeline. In this case, you are sending process
objects to Format-Table, which then displays two properties: StartTime and
MainWindowTitle, which were previously unavailable.
Microsoft Confidential
Page 79 of 361
As you can see, you can use more than a single pipe in a command to make it more useful.
Here, a few aliases are used to make the command fit on a single line, but the task
performed is passing objects along four different commands in the pipeline. The output of
each command is always passed from left to right along the pipeline.
Some Cmdlets however, do require all of the possible input before they can produce any
output, such as the case with Sort-Object. In the example above, Sort-Object needs to know
the working set of every process before it can sort them according to that property.
1. When piping data, usually things will show up very quickly, which can make it seem like
data gets sent along the pipeline instantly:
1..5
1..5 | Sort-Object -Descending
Here, you start by creating an array of numbers from one to five using the range operator
(..). Since there are no additional commands on the pipeline, PowerShell outputs those
numbers to the console. When you pipe that range of numbers to Sort-Object, it changes
the order of the numbers as they get passed along the pipeline.
2. Using the ForEach-Object Cmdlet, you can slow down the data being sent along the
pipeline.
1..5 | ForEach-Object { Start-Sleep 1; $_ }
Microsoft Confidential
Page 80 of 361
Here you can see the numbers one through five displays with a one-second delay between
each one. Each object gets passed along the pipeline and, in this case, it outputs them to
the console.
3. However, not every Cmdlet can process the pipeline data asynchronously.
1..5 | ForEach-Object { Start-Sleep 1; $_ } | Sort-Object -Descending
Here you see a 5 second delay before anything actually happens because Sort-Object
cannot process the data asynchronously. Sort-Object is a command that needs to receive
all of the pipeline data before it can decide what the appropriate sort will be. After the
initial delay, however, the numbers all appear almost instantly because Sort-Object
sends all of the data along the pipeline once it is finished processing.
4. To slow down the data as it is passed further along the pipeline, you can move the
ForEach-Object Cmdlet after the sort.
1..5 | Sort-Object –Descending | ForEach-Object { Start-Sleep 1; $_ }
Now you can see that the data is sorted first, quickly, before it is slowed down in the
ForEach-Object loop before being output.
5. If you were to use the output of a Cmdlet rather than a range of numbers, you would see a
similar result.
Get-Process | Sort-Object –Descending | ForEach-Object { Start-Sleep -m 250; $_ }
The process objects from Get-Process are passed along the pipeline one at a time. In this
example, you can see each running process with a 250 millisecond delay between each
one. In all the examples so far, you have been treating the pipeline variable as a single
unit. However, in reality there are more behind the scenes.
6. Consider the members available to each object output by Get-Process.
Get-Process | Get-Member
You can see that there are several properties available. The pipeline variable applies to
the entire object. In the case of Get-Member, it has to inspect each object to provide
feedback to the user about the available members, since not every object on the pipeline
will be of the same type. Get-Process contains the same type of object so all you see are
members of the System.Diagnostics.Process type.
7. Now, consider a directory.
Get-ChildItem C:\Windows | Get-Member
In this case, you can see that there are both System.IO.FileInfo and
System.IO.DirectoryInfo objects being passed along the pipeline.
8. Get-Member is another Cmdlet that processes data asynchronously.
Get-ChildItem C:\Windows\s*.*
When you run the command above, the Cmdlet returns directories before files in the list.
Microsoft Confidential
Page 81 of 361
9. You can add a delay to this command before sending it along the pipeline to Get-Member.
Get-ChildItem C:\Windows\s*.* | ForEach-Object {Start-Sleep 1; $_ } | Get-Member
Now you will see the type information come back slowly. This is because Get-Member
will only pass unique type information along the pipeline and, therefore, you have to wait
for each of the objects and their associated sleep command to occur.
10. What you have seen is that $_ refers to only a single object along the pipeline. However,
each object has individual members and the pipeline variable provides access to all of
them for each individual object.
Get-ChildItem C:\Windows\s*.* | ForEach-Object { $_.Name; $_.LastWriteTime }
Here you can see that the ForEach-Object Cmdlet allows you to access the name and
last write time for each object that is passed along the pipeline to it.
Microsoft Confidential
Page 82 of 361
Scenario
There are a number of different Cmdlets that allow you to modify the order of data that is
passed along the pipeline. In this exercise, you will look at some of the most common
Cmdlets that are used in this process.
The Get-Process Cmdlet, for example, has parameters that allow you to control which
process objects are passed back along the pipeline. However, you may need to be more
restrictive of that data than the Cmdlet allows. There are also times where you may need to
display data that does not show by default or change the order of what is passed along the
pipeline.
Log on to VM Environment
Log on to the Windows 7 Enterprise client
Here you can see that the display returns different information than what is returned by
Get-Process and Get-ChildItem when run by themselves. Using the default “property”
parameter allows you to specify an array of properties to pass further along the pipeline.
In the second command you can use the built-in alias: Select.
2. Sometimes you may want to return more detailed information than a basic property value.
In the previous Get-ChildItem example, you selected the length property, which is used
for file size in bytes. If you want to change it so that it displays in megabytes, you can
provide a custom property through a hash table.
gci | Select Name, @{Name=”Size(MB)”;Expression={[Math]::Round($_.Length/1MB, 2)}}
Microsoft Confidential
Page 83 of 361
The hash table that you provide has two key/value pairs.
The first is called Name and specified the name of the property that will be displayed.
This will show as the column heading in table format or the label in list format.
The second value is an expression provided as a code block, which uses the Math
class to round the file size to two decimal places after dividing by 1MB.
3. Select-Object allows you to change the properties that are returned as well as the number
of objects that are passed along.
Get-Process | Select ID, Name, WS -First 5
Get-Process | Select ID, Name, WS -Last 10
In the example above, the Select-Object Cmdlet is instructed to only select the first 5
objects from the pipeline (in the first example) or the last 10 objects (in the second
example).
4. There is also a parameter called Index, which will return only the nth item from the
pipeline.
Get-Process | Select -Index 10
Depending on what applications your system is running, you could see a wide variety of
processes returned here. However, it will only be a single process, and if you look at the
full list that Get-Process returns by itself, you will see that it is the 11th process on the list.
It is the 11th item from the list because the Index is 0-based, meaning our first item is
index 0, second item is index 1, and so on. This concept ties in with arrays as well, which
are also 0-based in PowerShell.
5. It is important to note that Select-Object modifies the objects being passed along the
pipeline.
Get-Process | Select ID, Name, WS | Get-Member
When you pass a Select-Object to Get-Member, the data changes and you no longer
have a full representation of the object that was passed into Select-Object. In the case
above, you will notice that all of the extra properties that were not included in the
Property parameter are now missing from Get-Member’s output. Any other properties
are now unavailable to any remaining commands on the pipeline. If you were to try sort
your output after this by the CPU utilization (which was not included in the Select) you
would not see the order change because the CPU property is missing.
6. In addition to Select-Object, there are a few other Cmdlets that are used for controlling
the properties that are displayed on the screen: Format-List and Format-Table. These
Cmdlets both allow you to specify the properties.
Get-Process | Format-List -Property ID, Name
Get-Process | FL ID, Name, CPU, WS
Microsoft Confidential
Page 84 of 361
The Format-List Cmdlet simply takes the data and converts it into a format where your
key and value pair are listed horizontally. The second command uses the built-in alias for
Format-List: FL
7. Typically, objects get output to the screen in a tabular format based on the configuration
files mentioned earlier. However, sometimes that output will default to a list format.
When it does, you can use Format-Table to force it to display as a table.
Get-Service | Format-Table -Property Name, Status
Get-Service | FT Name, Status -AutoSize
The Format-Table Cmdlet also has an autosize parameter, which controls how much of
the screen is taken up by the output. PowerShell attempts to determine the most
appropriate display format when using this parameter. The second example uses the built-
in alias for Format-Table: FT.
8. Like the Select-Object Cmdlet, Format-Table and Format-List also change the data
that is passed along the pipeline. However, these Format commands do it drastically.
Get-Process | FL ID, Name, CPU, WS | Get-Member
What you can see from the Get-Member output is that you have a number of different
objects that are being passed along the pipeline by the Format-List command. This
change in the object makes it impossible to access any of these properties again.
9. You can use a Sort-Object Cmdlet to order data after a Select-Object Cmdlet, but not
with Format-List or Format-Table.
Get-Process | Select ID, Name, CPU, WS | Sort-Object WS
Get-Process | FL ID, Name, CPU, WS | Sort-Object WS
The first command will properly sort the data. This is not a recommended format for
writing this command. The Select-Object Cmdlet is still changing the data so if you were
to try to sort by virtual memory size (VM) instead of working set (WS) no sorting would
actually take place, since the VM property is gone.
The second command with Format-List is more drastic and throws an error. The error
that is thrown relates to the fact that Format-List changes the data so drastically that it is
no longer valid input for a command like Sort-Object.
Microsoft Confidential
Page 85 of 361
Here you are instructing Where-Object to only return objects of which the working set is
greater than 50 megabytes. Where-Object goes through each item in the pipeline,
changing the pipeline variable each time, and executes the filter script to check if the
filter is true or false. If the filter script is true for that item in the pipeline, it is then passed
on to the next command.
2. Where-Object also has a few built-in aliases, one of which can sometimes confuse
people who are new to PowerShell.
Get-Process | Where { $_.Name -eq “notepad” }
Get-Process | ? { $_.Threads.Count -gt 25 }
The second example, using a question mark, can look confusing. However, it is a simple
alias used for Where-Object and is the number 2 spot atop the list when you execute the
Get-Alias Cmdlet with no parameters in a standard PowerShell instance.
3. Going back to the Select-Object Cmdlet, there is one additional parameter it provides,
which helps to filter data along the pipeline.
Get-Process | Select Name -Unique
Every version of Windows in the recent past will run a number of services that hosted
within the same executable running as separate instances. You could have multiple
PowerShell, ISE, or notepad instances running, among others. The Unique parameter
allows you to filter out duplicate objects and only return those that are distinct.
Note: The property parameter name is optional and Sort-Object has a built-in alias
called Sort.
2. When sorting objects, take note of where in the pipeline these objects are.
Get-Process | Sort WS | Select -First 10
Get-Process | Select -First 10 | Sort WS
These two commands have very different meanings. In the first command you are getting
the 10 processes with the smallest working set because you:
Sorted first along the pipeline
Then limited the selection to the first 10
The second command, since you selected the first 10 process objects, will sort only those
first ten objects. It will therefore (very likely) not be the same list of 10 processes.
Microsoft Confidential
Page 86 of 361
3. Sort-Object also allows you to change the order of the sort by using the Descending
parameter, which can be shortened to Desc.
Get-Process | Sort WS –Desc | Select -First 10
In the example above, you are getting the 10 largest processes by working set rather than
the smallest 10 as in the previous example.
4. When working with text data, you can also tell Sort-Object to sort case-sensitively.
"abC", "ABc", "deF", "aBc", "DEF", "def" | Sort-object –CaseSensitive
This command changes the sort, since lower-case letters are considered to be of lower
value than upper-case letters, just as when you examined the comparison operators.
5. Sort-Object also allows you to only sort unique objects.
"abC", "ABc", "deF", "aBc", "DEF", "def" | Sort-object -Unique
In this case, because you are no longer doing a case sensitive sort, the Cmdlet sees that
there are a number of duplicates. Thus, the result set is limited to a sorted “aBc” and
“def”. These are chosen from the list because they are the individual unique items found
last in the pipeline.
6. If you want to get unique objects, it may be more useful to use the Group-Object Cmdlet.
This will allow you to maintain all of the items that are found to be duplicates.
"abC", "ABc", "deF", "aBc", "DEF", "def" | Group-Object
The data returned with Group-Object will, by default, group the data into GroupInfo
objects that contain each individual item for each group. The name of each group will be
the first unique value found for each one: in this case, “abC” and “deF”, unlike Sort-
Object -Unique.
Microsoft Confidential
Page 87 of 361
Scenario
Since the pipeline only goes from left to right, you should be able to provide some kind of
input to the pipeline that cannot be generated from an initial cmdlet or function. To do this,
PowerShell provides a number of simple commands to input and output data to and from the
pipeline.
Log on to VM Environment
Log on to the Windows 7 Enterprise client
This command writes “winrm” to a file called services.txt. Open the file with notepad to
verify the data was written, then close notepad. Set-Content can also be called by its
built-in alias sc.
2. Append data to the file using Add-Content.
Add-Content -Path c:\pshell\part1\lesson3\services.txt -Value “wuauserv”
Add-Content c:\pshell\part1\lesson3\services.txt “netlogon”
Here you are using Add-Content to append data to an existing file. If the file did not
exist, a new one would have been created. Re-open the file in notepad to verify that you
have five service names listed (each on a separate line), then close notepad.
3. You can also pipe data to Set-Content and Add-Content.
“winlogon”, “dnscache” | ac c:\pshell\part1\lesson3\services.txt
This command takes the pipeline data of a text array and sends it in by value to the Add-
Content Cmdlet, appending each pipeline object as a new line within the services.txt file.
Additionally, you are calling Add-Content by its built-in alias.
Microsoft Confidential
Page 88 of 361
4. Set-Content and Add-Content were designed to work with string data. So, if you pass
non-string data to them, PowerShell will convert the objects to strings before writing to
the file.
Get-Process | Set-Content c:\pshell\part1\lesson3\processes.txt
If you open this processes.txt file in notepad, you will see that there is a line item for each
process running on your machine. Unfortunately, the actual information contained on
each line is the string conversion output from a Process object. You can see this by
calling the ToString() method of any process object.
Get-Process | ForEach-Object { $_.ToString() }
5. Set-Content and Add-Content stop the pipeline of data, unless you explicitly tell them
to continue it with the -Passthru parameter. When you use Passthru, you can actually
see the data that gets written to the file.
Get-Process | Set-Content c:\pshell\part1\lesson3\processes.txt -Passthru
In previous steps, you output data to the text file, but were unable to see what was written
there and had to either open the file or look at the value of the ToString() method for
each process. The -Passthru parameter allows this data to be passed along the pipeline so
you can actually see that data, or perhaps take further action upon the objects that were
passed into it.
6. Now that you have created a few files, you can also try to read from them with another
Cmdlet, Get-Content.
Get-Content c:\pshell\part1\lesson3\services.txt
You can see that the data from the file is output to the screen. Each line from the file is
returned as a separate object on the pipeline and each one is a string.
7. Since the Get-Service Cmdlet allows pipeline input for the Name parameter, you can
then take this data and pipe it to Get-Service.
Get-Content c:\pshell\part1\lesson3\services.txt | Get-Service
This command then returns the designated services specified in the file.
Microsoft Confidential
Page 89 of 361
AC c:\pshell\part1\lesson3\people.csv “Thomas,Andersen,Revolutionary”
Open the file in notepad to confirm there are six lines of text starting with the header and
five individuals. Close the file when finished.
2. Now that you have a CSV file to work with, reading it in with PowerShell is quite simple.
Import-CSV c:\pshell\part1\lesson3\people.csv
When you execute this command, it turns the data from the file into objects that get
passed along the pipeline. Each object has properties that correlate with the column
headers from the CSV file. You can also change the delimiter for each value or set the
header information manually if you prefer using the appropriate parameters.
3. You can work with the imported data like any other pipeline data.
ipcsv c:\pshell\part1\lesson3\people.csv | Sort Surname | Select GivenName
Here you are calling Import-CSV using its built-in alias. Then, you are piping the data
out to Sort-Object and Select-Object.
4. Exporting data to a CSV is even easier and provides considerably more information than
when using Set-Content and Add-Content.
Get-Process | Export-CSV c:\pshell\part1\lesson3\processinfo.csv
Here you piped some data to the Export-CSV Cmdlet and PowerShell wrote all the
properties to the file for each individual object, setting appropriate headers in the file.
5. Just like Import-CSV you can also change the headers, delimiter and some other
information. It is important to note that, Export-CSV will overwrite any file that already
exists and there is no built-in functionality for appending to a CSV.
Get-Process | Select –First 10 | epcsv c:\pshell\part1\lesson3\processinfo.csv
Here you are limiting process selection to the first 10 objects and then sending them to
Export-CSV using its built-in alias. When you open the processinfo.csv file now, you
will see that it completely overwrote the old data from the previous example.
6. If you wanted display this data on the screen instead of writing it to a file, you can use the
ConvertTo-CSV Cmdlet.
Get-Process | Select id, name –First 10 | ConvertTo-CSV
This displays that data as text to the screen because it was passed along the pipeline
rather than out to a file. You can then take that output and send it to another Cmdlet, such
as Send-MailMessage to email it to yourself for later use.
7. The ConvertTo-HTML Cmdlet can be even more useful by taking data and turning it
into an HTML table. It works similar to the ConvertTo-CSV Cmdlet, but gives you more
functionality and converts to HTML.
Get-Process | ConvertTo-HTML > c:\pshell\part1\lesson3\processinfo.html
Microsoft Confidential
Page 90 of 361
If you open this file with Internet Explorer, you will see a basic HTML table has been
created. If you are familiar with HTML, you can look at the source and you will see it has
properly formatted everything in a standard TABLE element. There are additional
parameters available to alter the output by specifying a CSS file to use for styling or to
add data to the Head, Title, Body, and other areas of the document.
Note: There are a few additional ConvertTo-* Cmdlets included with PowerShell, for
more information use Get-Help ConvertTo-*
Microsoft Confidential
Page 91 of 361
Prerequisites
The lab requires a Windows 7 client running in a domain environment.
Microsoft Confidential
Page 92 of 361
Scenario
Now that you know how WMI can be accessed in Windows, you can use PowerShell 1.0 or
2.0 to get information from it. This exercise concentrates on getting only local information.
On the windows task bar locate the icon. Click on this icon.
The PowerShell window will open.
You will see the services that are currently running on your workstation. This is because
the list of services was passed from the Get-Service Cmdlet to the Where-Object
Cmdlet. Using the equals operator, the Where-Object Cmdlet only displays services
whose status is equal to running. You can reverse the logic by using the not equals to
operator
2. From PowerShell console, run the following command
Get-service | where-object {$_.status –ne “Running”}
You will now see the services that are not running.
You can also use the operators to look at other objects. Now, look for PowerShell script
files in the c:\pshell directory.
3. In the PowerShell console, type the following command to search for files:
Microsoft Confidential
Page 93 of 361
You will now see any *.ps1 files in the c:\pshell tree.
You can also look for files with other properties. Look for files that are greater than a
particular size.
4. Type the following into the PowerShell console to list all the files from the root of c:
Get-childitem c:\
You will now see all the files that are in c:\. Next let’s look for any files that are greater
than 1KB
5. Type the following command in the PowerShell console to find files greater than 1Byte
Get-childitem c:\ | where-object {$_.length –gt 1}
You will now see the list of files greater than 1 byte.
6. Type the following command in the PowerShell console to find files greater than 1KB
Get-childitem c:\ | where-object {$_.length –gt 1kb}
You will now see the list of files greater than 1KB. Note that this works as KB is a byte
constant in PowerShell. This means that 1KB = 1024 bytes to make it easier to reference
byte values in PowerShell. To extend this further, you will now use 1MB also.
7. Type the following in the PowerShell console to find files greater than 1MB
Get-childitem c:\ | where-object {$_.length –gt 1mb}
You will now see any files that are greater than 1MB.
Microsoft Confidential
Page 94 of 361
On the windows task bar locate the icon. Click on this icon.
The PowerShell window will open.
This will assign the contents of the computers.txt file to the variable.
2. Type the following command in the PowerShell console to display the list of computers.
$computers
Note: Each computer’s name is passed to the foreach-object one at a time using the
$_ variable. The ping command uses this name to perform the ping.
Microsoft Confidential
Page 95 of 361
This can also be used with other objects, such as files on your computer.
From the PowerShell console, run the following command:
Get-childitem c:\pshell
You will now see the full name displayed for any folders in c:\pshell.
Expanding on this, you may want to know how many files or folders are under each sub-
directory and the total size of each of these folders.
First, try the command on the c:\pshell folder.
6. From PowerShell console, run the following command to display the count and total size
of the files in c:\pshell. To reduce the size of the command, use aliases.
Gci c:\pshell –recurse | measure-object length –sum
You will now see displayed the count of files and the sum of the files for the c:\pshell
directory.
Using the foreach-object Cmdlet and the pipeline do the same for each top level
directory in the c:\pshell path. To do this you will combine the commands used in
previous steps.
Get-childitem C:\pshell | where {$_.psiscontainer} | foreach-object {$_.fullname ;
gci $_.fullname –recurse | measure-object length -sum}
You will now see displayed the file count and total size of the files for each sub directory
The next example uses services.
7. From the PowerShell console, run the following command to display running services:
Get-service | where-object {$_.status –eq “Running”}
Microsoft Confidential
Page 96 of 361
This can also be done with the foreach-object Cmdlet although this does require more
code. This is also using an if statement. This will be covered in more detail in the
scripting lesson.
8. From the PowerShell console , run the following command to display running services:
Get-service | foreach-object {if ($_.status –eq “Running”) {write-host “$($_.name)
: $($_.status)”}}
Running services will now be displayed. As you are using the write-host Cmdlet you can
also add color to the display.
9. From the PowerShell console , run the following command to display running services
with color:
Get-service | foreach-object {if ($_.status –eq “Running”) {write-host “$($_.name)
: $($_.status)” –foregroundcolor green}}
You will now see the running services displayed in green. Expanding on this you can also
display services not running as red by modifying the if statement.
10. From the PowerShell console, run the following command to display running services
with color:
Get-service | foreach-object {if ($_.status –eq “Running”) {write-host “$($_.name)
: $($_.status)” –foregroundcolor green} else { write-host “$($_.name) :
$($_.status)” –foregroundcolor red}}
You will now see displayed the services and their status in:
Green for running
Red for services that are not running
You might notice that the names of the services are the short names. If you modify the
command above to use $_.displayname instead of $_.name you will see the friendly
name of the service displayed.
11. From the PowerShell console, run the following command to display running services
with color using their displayname:
Get-service | foreach-object {if ($_.status –eq “Running”) {write-host
“$($_.displayname) : $($_.status)” –foregroundcolor green} else { write-host
“$($_.displayname) : $($_.status)” –foregroundcolor red}}
You will notice that the display is not sorted and that the data is displayed as a table
starting with status, name and displayname. You can change this by using the sort-object
Cmdlet.
12. Type the following to sort the services by their status.
Get-service | sort-object status | foreach-object {if ($_.status –eq “Running”)
{write-host “$($_.displayname) : $($_.status)” –foregroundcolor green} else {
write-host “$($_.displayname) : $($_.status)” –foregroundcolor red}}
You will now see the services displayed sorted by their status with color.
Microsoft Confidential
Page 97 of 361
Note: The use of the foreach-object here is to showcase the use of the pipeline and
the processing of each item passed through the pipeline. There are much better ways
of performing the above activities.
Microsoft Confidential
Page 98 of 361
On the windows task bar locate the icon. Click on this icon.
The PowerShell window will open.
The list of running processes will now be displayed. Now, filter the display to look for
specific processes.
2. From the PowerShell console, run the following command to display running processes
starting with s:
Get-process | where-object {$_.name –like “s*”}
Microsoft Confidential
Page 99 of 361
The list of running processes consuming more than one second CPU time will now be
displayed.
These can also be combined into one command using the –or and –and operators.
4. Type the following command to filter processes
Get-process | where-object {$_.name –like “s*” –or $_.cpu –gt 1}
You will now see that the services are now sorted by their status. However, the output is
still displayed as the default table and the stopped services are displayed first.
Note: By default PowerShell will perform ascending sorts. You can change this by
adding the -descending option to the command
7. From the PowerShell console, run the following command to sort the services by status in
descending order:
Get-service | sort-object status -descending
Now you will see the running services first and then the stopped services. The following
examples deal with changing the output displayed.
8. From the PowerShell console, run the following command to sort services and change the
display:
Get-service | sort-object status –descending | format-table name, displayname,
status
You will now see the services and their status in a table with the service name,
displayname and the status. You will notice that there are some truncated names and
some is space lost. This is because the format-table Cmdlet uses a default column size
without looking at the data returned. You can change this by using the -autosize
parameter.
9. In the PowerShell console, type the following command to sort the services and see the
result of the -autosize option:
Microsoft Confidential
Page 100 of 361
You will now see that the display is much better as it does not truncate the names and
does not waste any white space.
However, you will notice that the services are now sorted by their status and not by their
name or displayname. This can be addressed by adding name to the sort-object Cmdlet
10. In the PowerShell console, type the following command to sort services and see the result
of the -autosize option:
Get-service | sort-object status, name –descending | format-table displayname,
status –autosize
You will now see the services sorted by their status and name. However, note that
because you used the -descending parameter the sort is descending. If you remove this
parameter, the sort will be ascending.
11. In the PowerShell console, type the following command to sort services and see the result
of the -autosize option:
Get-service | sort-object status, name | format-table displayname, status –
autosize
You will now see the services displayed and sorted by their name. However, the status is
reversed as S comes before R in the alphabet.
If you use the sort-object Cmdlet normally, you have to choose if the whole sort will be
ascending or descending. However, this is a way of having one property sorted in
ascending order and the other in descending order. This is done via an expression hash
table.
12. In the PowerShell console, type the following command to sort services using the
expression hash table:
get-service | sort-object -property @{Expression="Status";Descending=$true},
@{Expression="Name";Descending=$false} | format-table displayname, status –
autosize
Now you will see the services displayed and sorted with the names in ascending order
and the status in descending order.
You may want services to use the displayname instead of the short name. You can do this
by modifying the command.
13. Type the following to sort services using the expression hash table.
get-service | sort-object -property @{Expression="Status";Descending=$true},
@{Expression="DisplayName";Descending=$false} | format-table displayname, status
–autosize
You will now see the services displayed and sorted by displayname and then status.
Microsoft Confidential
Page 101 of 361
Finally, you might want to save this information to a file. This can be easily done by
using the redirector operator and specifying a filename.
14. Type the following to sort the services using the expression hash table:
get-service | sort-object -property @{Expression="Status";Descending=$true},
@{Expression="DisplayName";Descending=$false} | format-table displayname, status
–autosize > servicestatus.txt
Microsoft Confidential
Page 102 of 361
Microsoft Confidential
Lesson 4 Demonstration : Providers
Introduction
This lesson will introduce you to the concept of the PowerShell provider model and their use.
It will introduce you to what providers are available, what data the providers contain and how
to operate with the providers.
Objectives
After completing this lab, you will be able to:
Understand the concept of PowerShell providers
Use PowerShell providers and drives to access various different information sources
Understand which providers are single level and multiple level
Create items in different providers
Prerequisites
To complete this lab, you need:
A Windows 7 workstation logged onto with administrator credentials
Microsoft Confidential
Page 104 of 361
Scenario
The PowerShell provider model is a system built into PowerShell to allow you to access
different data sources like you access data in a file system. This is achieved by a system of
providers and PowerShell drives. There are several providers and drives already built into
PowerShell to allow you to access various different data types. It is possible to add additional
providers to PowerShell
PS C:\Users\administrator> Get-PSProvider
Microsoft Confidential
Page 105 of 361
You will see that now you have displayed the names of the providers available, their
capabilities, and the drives associated with them.
While it is useful to see the PowerShell providers listed, this may not be how you would
think of them in terms of accessing information from them. You are more likely to use
them, or think of them as drives.
PS C:\Users\administator> Get-PSDrive
Now, you will see the list of PowerShell drives that are available.
You will see the name of the drive that you will use to set the location, the provider that
is presenting the drive, and file system details such as used and free space for the file
system drives.
Microsoft Confidential
Page 106 of 361
1. In the PowerShell console, type the following command to set the current location to the
alias drive:
set-location Alias:\
PS Alias:\>
PS HKLM:\software>
PS HKLM:\>
Microsoft Confidential
Page 107 of 361
6. In the PowerShell console, type the following command to set the location back to your
home location:
Set-location $home
PS C:\Users\administrator>
You will see that you can use variables for path locations and that the current location
will have changed to the location you want.
Microsoft Confidential
Page 108 of 361
Scenario
When using any of the PowerShell providers, there are many Cmdlets that are related to
working with information accessible via the providers. Many of these Cmdlets work in the
same or a similar way for each provider. To identify the Cmdlets related to the providers,
break them down into three groups.
First Group: Cmdlets that work with the providers and drives
Second Group: Cmdlets for navigation and path related operations
Third group: Cmdlets for working with the items, properties and contents of the
information accessible via providers
Microsoft Confidential
Page 109 of 361
This can be fixed by creating a new PowerShell drive and setting its path to the required
hive. You need to provide the drive name, specify the provider that the information is
coming from, and the root path to which you want to map.
3. In the PowerShell console, type the following command to create a new PowerShell
drive:
new-psdrive –name HKCR –psprovider registry –root HKEY_CLASSES_ROOT
A drive called HKCR is created and it will contain the information from the hkey classes
root registry hive.
4. In the PowerShell console, type the following command to list the PSdrives:
Get-psdrive
6. In the PowerShell console, type the following command to set the location to the new
drive:
set-location mydocs:
You will see that the prompt has changed to PS mydocs:\> indicating that you are in the
mydocs drive.
7. In the PowerShell console, type the following command to list the contents of the drive:
Get-childitem
The list of files and folder available from the mydocs drive appears.
Along with creating new drives, you can also remove drives. Note that this should only
be used on additional drives you have created and not on inbuilt drives.
8. In the PowerShell console, type the following command to set the location back to C:.
Set-location c:
9. In the PowerShell console, type the following command to remove the mydocs drive:
Remove-psdrive –name mydocs
This will remove the mydocs drive from the current shell. You can confirm this with get-
psdrive.
10. In the PowerShell console, type the following command to list the available PowerShell
drives.
Microsoft Confidential
Page 110 of 361
Get-psdrive
The result, indicating that C:\ path is valid appears. If you test for a location that does not
exist or file that does not exist the result will be false.
2. In the PowerShell console, type the following command to test the path C:\fakefolder:
Test-path c:\fakefolder
Again, a false is returned as this file does not exist. Let us try a file that does exist.
4. In the PowerShell console, type the following command to test the file
C:\fso\servers.txt:
Test-path c:\fso\servers.txt
Microsoft Confidential
Page 111 of 361
Note: The current location must be a file system provider location or the UNC will
return false regardless if it exists or not. This is also true when using set-location on
UNC paths. You must first be in a file system provider location.
Let us now look at something other than the file system. You can test to see if an
environment variable exists.
6. In the PowerShell console, type the following command to test the systemroot
environment variable:
Test-path env:\systemroot
4. In the PowerShell console, type the following command to view the value of $mypath:
$mypath
Microsoft Confidential
Page 112 of 361
2. In the PowerShell console, type the following command to add the location to the stack:
Push-location
3. In the PowerShell console, type the following command to set the location to env: drive:
Set-location env:
4. In the PowerShell console, type the following command to add the location to the stack:
Push-location
5. In the PowerShell console, type the following command to set the location to the hklm:
drive:
Set-location hklm:
The current location changes to the last location from where you ran push-location, PS
Env:\>.
7. In the PowerShell console, type the following command to change to the next location
from the stack:
Pop-location
The prompt changes to the first location from which you ran push-location.
2. In the PowerShell console, type the following command to resolve the path *program*:
Microsoft Confidential
Page 113 of 361
Resolve-path *program*
Path
----
C:\Program Files
HKEY_LOCAL_MACHINE\software\microsoft
Microsoft Confidential
Page 114 of 361
work in a similar way for all the providers. This allows a standard syntax to be used
irrespective of the individual provider or item in use.
The Cmdlets that work with items, item properties and content are:
Clear-item
Copy-item
Get-item
Invoke-item
Move-item
New-item
Remove-item
Rename-item
Set-item
Clear-itemproperty
Copy-itemproperty
Get-itemproperty
Invoke-itemproperty
Move-itemproperty
New-itemproperty
Remove-itemproperty
Rename-itemproperty
Set-itemproperty
Add-content
Clear-content
Get-content
Set-content
The best way to explore using these is to use them in the context of providers. You will try
this in the next exercise.
Microsoft Confidential
Page 115 of 361
Scenario
When working with PowerShell providers they can be split into two major groups:
Single level providers
Multiple level providers
This exercise will focus on single level providers. Single level providers are providers that
use the file system model and do not have sub folders. That is, all items of interest are
effectively located in the root of the drive.
The single level providers available are:
Alias provider
Environment provider
Function provider
Variable provider
3. In the PowerShell console, type the following command to list the aliases:
Get-childitem
Microsoft Confidential
Page 116 of 361
You can also create a new alias using the new-item Cmdlet.
5. In the PowerShell console, type the following command to create a new alias:
new-item –name myalias –value get-help
2. In the PowerShell console, type the following command to list the environment variables:
Get-childitem
The list of environment variables available appears. You can also get a particular variable
of interest.
3. In the PowerShell console, type the following command to get the systemroot variable:
Get-item systemroot
The systemroot variable will now appear. You can also address using the full path to the
item from any location.
4. In the PowerShell console, type the following command to set the location to C: drive:
Set-location c:
5. In the PowerShell console, type the following command to get the systemroot variable
with full path:
get-item env:\systemroot
Microsoft Confidential
Page 117 of 361
You can also create new environment variables using the new-item Cmdlet. However,
note that these are not permanent. Variables created here will only be available to the
current PowerShell console session. The variable will be deleted when the current session
expires. If you need to create a new permanent variable, then you will have to create the
variable in the registry, or via the control panel.
There is an alternative way of getting the value of an environment variable. This is by
using $env:<variablename>.
6. In the PowerShell console, type the following command to get the windir value:
$env:windir
2. In the PowerShell console, type the following command to list the contents of the drive:
Get-childitem
The list of functions currently defined appears. You will notice the 26 functions, A: to Z:.
These are not aliases. The reason they are not aliases is because, they are not only a
reference to Cmdlet, but are set-location <driveletter>. An alias is only a different name
of a Cmdlet, the only way the A: to Z: commands can work is through a function.
Let us filter out the A: to Z: functions so that you can see the other functions.
3. In the PowerShell console, type the following command to filter the A-Z functions:
get-childitem | where-object {$_.definition –notlike “set-location*”}
Microsoft Confidential
Page 118 of 361
It is also possible to create a new function here, test if a function is defined with test-path,
rename a function with rename-item, or delete a function with delete-item. The
definition or code to execute a function can also be changed.
Note: Ensure not to use this to change the inbuilt functions as this may cause unknown
issues with PowerShell.
2. In the PowerShell console, type the following command to execute the function:
myfunction
4. In the PowerShell console, type the following command to execute the renamed function:
ourfun
Note that this is not the correct way to create functions. This was only to demonstrate the
function provider. The correct way to define functions will be covered in module 6.
2. In the PowerShell console, type the following command to list the contents of the drive:
get-childitem
The currently defined variables and their values appear. Note that the names of the
variables do not include $. The $ sign is used to tell PowerShell that you are working
with a variable. It is not actually part of the variable name.
Microsoft Confidential
Page 119 of 361
As with all providers, you can test if a variable exists, create new variables, or rename
them. These operations can also be performed using the assignment operator.
2. In the PowerShell console, type the following command to get the value of $deleteme:
$deleteme
The variable is deleted from all locations as you have specified the full path to the object.
Deleting a variable can also be done using remove-variable. Both of these will result in
the variable being destroyed (not set to null or blank). This is important if the information
stored in the variable is critical.
Microsoft Confidential
Page 120 of 361
Scenario
In addition to single level providers, PowerShell also has multiple level providers. The major
difference between single level providers and multiple level providers is that the multiple
level providers have containers as well as items contained in them. This presents the
information available via the provider as in a file system. A file system also has items,
containers and sub containers.
The multiple level providers available are:
Filesystem provider
Registry provider
Certificate provider
WSman provider
3. In the PowerShell console, type the following command to list the contents:
Get-childitem
Two containers are now available, the CurrentUser and LocalMachine containers.
Let us navigate to the local machine folder.
4. In the PowerShell console, type the following command to set the location to the local
machine container:
Set-location cert:\localmachine
5. In the PowerShell console, type the following command to list the contents:
Get-childitem
The list of certificate stores for the local machine appears. If you change your location to
one of these stores, you can see the certificates in it.
Microsoft Confidential
Page 121 of 361
6. In the PowerShell console, type the following command to set the location to the ca
container:
Set-location ca
7. In the PowerShell console, type the following command to list the contents:
Get-childitem
The list of certificates appears. Note that thumbprint is the name of the certificate used
when using the item Cmdlet. As thumbprints are not very friendly, it is highly
recommended that you enable quick edit mode for PowerShell to allow you to cut and
paste.
Let us now look at one of the certificates in detail.
8. In the PowerShell console, type the following command to get a certificate:
get-item tab
This will now get one certificate. There is more information available for the certificate.
To access this, pipe this to format-list *.
9. In the PowerShell console, type the following command to display the details of the
certificate:
get-item tab | format-list *
11. In the PowerShell console, type the following command to search for certificates that
have Microsoft in the subject:
get-childitem –recurse | where {$_.subject –like “*Microsoft*”}
The list of certificates in the localmachine store that contain Microsoft in the subject
name appears.
Microsoft Confidential
Page 122 of 361
set-location hklm:\
The containers accessible from the root of the HKLM drive appear. Note that the error
you get is expected. This is due to the security key that is accessible only by the system
account.
3. In the PowerShell console, type the following command to change the location of the
autorun programs for the system key:
Set-location .\software\Microsoft\powershell\1\shellids\Microsoft.PowerShell
The current location is now changed to the run key. From here, see the items you have.
4. In the PowerShell console, type the following command to list the contents:
Get-childitem
There is no result. This is due to the slightly different way the registry provider works.
The registry keys are represented as folders, but the registry values that you would expect
to be presented as items are not. They are properties of the key. That is, instead of using
the get-item, or get-childitem Cmdlets, you need to use the get-itemproperty Cmdlet to
read a value.
5. In the PowerShell console, type the following command to go one level up the tree:
Set-location ..
6. In the PowerShell console, type the following command to get the properties of the run
key:
Get-itemproperty –path .\Microsoft.Powershell
Only the value for Execution Policy appears, but this requires you knowing the name of
the value you want.
There is an easier way to do this using a method call on the registry key.
8. In the PowerShell console, type the following command to assign the registry key to a
variable:
$regkey = Get-item Microsoft.PowerShell
Microsoft Confidential
Page 123 of 361
9. In the PowerShell console, type the following command to get the value using a method
call:
$regkey.getvalue(‘ExecutionPolicy’)
You can also create registry keys using the new-item Cmdlet.
10. In the PowerShell console, type the following command to change the location to the
software key:
Set-location hklm:\software
11. In the PowerShell console, type the following command to create a registry key under the
software key:
New-item mysoftware
This will create the new registry key under the software key.
12. In the PowerShell console, type the following command to display the subkey of the
software key:
Get-childitem
The software key appears. Now, create a registry value. The path needs to be the registry
key under which you will create the value and you need to specify the name and value of
the registry property.
13. In the PowerShell console, type the following command to create a registry value:
New-itemproperty –path mysoftware –name myregvalue –value “This is my registry
value”
This will create the registry value as a string. You can also create dwords or other data
types by adding the –type parameter.
14. In the PowerShell console, type the following command to create a registry dword:
New-itemproperty –path mysoftware –name mydword –value “0x23” –type dword
15. In the PowerShell console, type the following command to check our registry values
created:
Get-itemproperty mysoftware
Microsoft Confidential
Page 124 of 361
2. In the PowerShell console, type the following command to display the contents of this
drive:
Get-childitem
The root of the drive contains one container, the localhost container. It is inside this
container that you find the configuration for various WinRM settings and components.
3. In the PowerShell console, type the following command to list the contents of the
container:
Get-childitem localhost | format-table -autosize
Some settings, and additional containers that contain further settings appear.
4. In the PowerShell console, type the following command to change to the client container:
Set-location localhost\client
5. In the PowerShell console, type the following command to display the contents of the
client folder:
Get-childitem
You can modify the values of these settings using the set-item Cmdlet. This will be
covered later in the PowerShell remoting lesson.
3. In the PowerShell console, type the following command to display the contents:
Get-childitem
Microsoft Confidential
Page 125 of 361
The contents of the C drive appear. This will include both files and folders. You can filter
the view such that you will only see files, or folders. To do this, use a property called,
psiscontainer.
4. In the PowerShell console, type the following command to display only folders:
Get-childitem | where-object {$_.psiscontainer}
Only the folders appear. Note that you can use the psisontainer property without an
operator as it is a Boolean value.
5. In the PowerShell console, type the following command to display only the files:
Get-childitem | where-object {!$_.psiscontainer}
Only the files appear. The ! sign represents a NOT operator and reverses the logic, so
look for objects where psiscontainer is false.
6. In the PowerShell console, type the following command to display the properties
available for files and folders:
Get-childitem | get-member –membertype *property*
The properties for both system.io.directory and system.io.fileinfo types appear. These
are .Net framework types that represent the files and folders on the system.
Note the properties with names that start with PS and are of type NoteProperty. These
are additional properties that are added to the display by PowerShell. This is because you
are accessing the items via the provider. These properties have useful information.
The PSChildname property contains the name of the item
The PSDrive property contains the PowerShell drive the item is from
The PSIscontainer property contains the container status of the item
The PSParentPath property contains the PowerShell parent path of the object. This
includes the provider reference
The PSPath property contains the full PowerShell path of the object. This includes
the provider reference
The PSProvider property contains the PowerShell provider that the object is from
These properties are added to any object accessed through a PowerShell provider.
7. In the PowerShell console, type the following command to create a new directory:
New-item –name myfolder –type directory
This will create a new directory. The type parameter is required. As the file system can
contain both files and directories, you need to define the object you are creating.
8. In the PowerShell console, type the following command to change the current location to
C:\myfolder:
Microsoft Confidential
Page 126 of 361
Set-location c:\myfolder
This will create a file. Note that the file length is current 0. This is a completely empty
file. It is also possible to create a file with data in it at the same time.
10. In the PowerShell console, type the following command to create a file with contents:
New-item –name machinenames.txt –type file –value “Machinenames”
This will create the file and populate it with the data from the value parameter.
11. In the PowerShell console, type the following command to read the data from the file:
Get-content machinenames.txt
13. In the PowerShell console, type the following command to add more data to the file:
Add-content machinenames.txt –value “w7client”
14. In the PowerShell console, type the following command to read the contents of the file
again:
Get-content machinenames.txt
Machinenamessyddc01
w7client
Notice that machinenames and syddc01 are on the same line. This is because, when the
file was created, the value specified was written to the file as it was. This did not include
a new line character. When the add-content commands were used, they added the new
line character. This should be taken care of.
15. In the PowerShell console, type the following commands to set the contents of the file:
Set-content machinenames.txt –value “Myservers”
add-content machinenames.txt –value “syddc01”
add-content machinenames.txt –value “w7client”
16. In the PowerShell console, type the following command to get the file contents:
Get-content machinenames.txt
The set-content Cmdlet will overwrite the file. This Cmdlet also adds a new line after
setting the contents. The add-content Cmdlet also does the same.
Microsoft Confidential
Page 127 of 361
17. In the PowerShell console, type the following command to rename the file:
Rename-item machinenames.txt –newname servernames.txt
18. In the PowerShell console, type the following command to list the files:
Get-childitem
This will delete the file. You can also delete directories.
20. In the PowerShell console, type the following command to create a new subdirectory:
New-item –name mysub1 –type directory
21. In the PowerShell console, type the following command to create a file in the
subdirectory:
New-item –path .\mysub1 –name deleteme.txt –value “delete this file” –type file
22. In the PowerShell console, type the following command to create a second subfolder:
New-item –name mysub2 –type directory
23. In the PowerShell console, type the following command to list the files and folders
recursively:
Get-childitem –recurse
Directory: C:\myfolder
Directory: C:\myfolder\mysub1
You now have an empty subdirectory and one with a file in it.
24. In the PowerShell console, type the following command to delete the mysub2 directory:
Remove-item mysub2
Microsoft Confidential
Page 128 of 361
Remove-item mysub1
You will be prompted to confirm that you want to delete the directory and all child items,
because the directory contained a file. If you want to perform this action without the
prompt you can specify the –recuse option. Use this carefully, as you will not be
prompted to confirm the action.
Microsoft Confidential
Page 129 of 361
Objectives
After completing this lab, you will be able to:
Work with the environment provider to create and test variables
Work with the certificate provider to search for certificates by their properties
Export the details of a certificate as a text file
Work with the registry provider to create registry keys
Work with the registry provider to create registry values
Edit registry values to filter out unwanted values
Prerequisites
To complete this lab, you need:
A Windows 7 workstation logged onto with administrator credentials
Microsoft Confidential
Page 130 of 361
Now, create multiple variables. This will only be available for the current session. You
can make a permanent environment variable by editing the registry.
2. In the PowerShell console, type the following command to create an environment
variable:
New-item –name AssetTag –value “12345ABCD”
3. In the Powershell console, type the following command to create another environment
variable:
New-item –name SOE_Version –value “WIN7_X86_CONTOSO_R1.2”
4. In the PowerShell console, type the following command to prompt for input:
$Department = read-host “Please enter your department”
The $department variable is expanded, and then the value for the department
environment variable is assigned.
Microsoft Confidential
Page 131 of 361
7. In the PowerShell console, type the following command to create a variable from other
variables:
New-item –name CurrentUser –value “$env:userdomain\$env:username”
This will export the current variables to a csv file. This file will contain all the properties
of the items, including their PS properties as well their name and values. The –
notypeinformation option is used to prevent PowerShell from including type information
in the file. This information is only useful when you are going to import information from
a csv and keep the type mapping.
2. In the PowerShell console, type the following command to view the csv file in Notepad:
Notepad c:\pshell\part1\lesson4\labs\variables.csv
2. In the new PowerShell console, type the following command to list the variables:
Get-childitem
The variables AssetTag, SOE_Version, department and current user no longer exist.
Now, import the variable details you exported to the csv file.
$myenv = import-csv c:\pshell\part1\lesson4\labs\variables.csv
3. In the new PowerShell console, type the following command to view the imported data:
$myenv
Microsoft Confidential
Page 132 of 361
The default view is a list and all the properties for each variable appear. You can change
this to display a similar view to the original variables.
4. In the new PowerShell console, type the following command to reformat the date:
$myenv | format-table name, value
A list of the variables and a true or false result if the variable current exists appear. The
command above uses the foreach Cmdlet that passes each item from the variable one at a
time to the script block section. The script block section is the {} part. This is a block of
code that will be run for each item. The script block uses the write-host Cmdlet and the
pipeline variable the $_ to display the name of each variable. It also tests if the variable
exists using the test-path Cmdlet.
Sub expressions can also be used with the $( ). This allows you to extract the value of the
name and value properties. You can create any variables that do not exist.
6. In the new PowerShell console, type the following command to create any variables that
do not exist:
$myenv | foreach {if (!$(test-path env:\$($_.name))) {new-item –path
env:\$($_.name) –value $($_.value)}}
This command uses the if statement and the result of the test-path Cmdlet to find any
variables that does not exist. If they do not exist, the new-item Cmdlet is executed to
create the variable and the value.
7. In the new PowerShell console, type the following command to list the variables:
Get-childitem
Microsoft Confidential
Page 133 of 361
2. In the PowerShell console, type the following command to change to the local machine
certificate container:
Set-location localmachine
The prompt will now be located in the localmachine certificate store. From here, you can
search for certificates given their properties.
First, search for certificates that have expired.
To do this, you need to create a value in datetime format to compare it to the value of the
certificates.
3. In the PowerShell console, type the following command to create a datetime value:
$today = get-date
4. In the PowerShell console, type the following command to search for the certificates that
have expired:
Get-childitem –recurse | where-object {$_.notafter –lt $today}
The certificates that have an expiry, or notafter property value less than today’s date
appear. You can also add them to a variable and filter out any containers that may be
included.
5. In the PowerShell console, type the following command to add the expired certificates to
a variable and filter out any containers:
$expiredcerts = gci -recurse | where {$_.notafter -lt $today -and $_.psiscontainer
-ne $true}
$expiredcerts will now contain the expired certificates. You can examine one of the
certificates using array addressing to look at that certificate.
Microsoft Confidential
Page 134 of 361
6. In the PowerShell console, type the following command to examine one certificate from
the variable:
$expiredcerts[0] | format-list *
The details for the first certificate in the variable appear. You can look at other
certificates using different numbers in between the [ ].
You can also look at valid certificates using a different logic.
7. In the PowerShell console, type the following command to search for current valid
certificates:
$validcerts = gci -recurse | where {$_.notafter -gt $today -and $_.notbefore -lt
$today}
9. In the PowerShell console, type the following command to check if the certificate is
valid:
$validcerts[0].verify()
You will see that the result is true, as this certificate is valid. You can test one of the
expired certificates that is not valid.
10. In the PowerShell console, type the following command to display the certificate subject
name:
$validcerts[0].subject
11. In the PowerShell console, type the following command to check if the certificate is
valid:
$expiredcerts[0].verify()
13. In the PowerShell console, type the following command to get the type of the certificate:
$expiredcerts[0].getformat()
14. In the PowerShell console, type the following command to certificate issuing authority:
$expiredcerts[0].getissuername()
Microsoft Confidential
Page 135 of 361
Microsoft Confidential
Page 136 of 361
3. In the PowerShell console, type the following command to assign the registry key to a
variable for later reference:
$mykey = get-item hklm:\software\contoso
6. Type the following command to check the value of the registry key property:
$mykey.getvalue(‘departments’)
This command will assign everything to the variable $newdepartments except the value
you filter with the where-object code, Silly_walks.
Microsoft Confidential
Page 137 of 361
8. In the PowerShell console, type the following command to check the contents of
$newdepartments:
$newdepartments
The names, Sales, Marketing, IT_Support, Legal, HR, Administration appear but not
Silly_walks. Note that all the work is done by the where-object Cmdlet using the –
notlike operator.
9. In the PowerShell console, type the following command to set the value of the property to
the new list:
Set-itemproperty –path hklm:\software\contoso –name departments –value `
$newdepartments
Microsoft Confidential
Page 138 of 361
Microsoft Confidential
Lesson 5 Demonstration : Variables and Type
Fundamentals
Introduction
In this module, we will learn about the different variables available in Windows PowerShell.
Along with the understanding of the usage of the variables, we will also look at the different
types of variables available in PowerShell. Each of them is used for a specific purpose.
Effective use of variables, arrays, and hash tables is a key for an administrator to prepare
scripts for daily administrative tasks.
Objectives
After completing this lab, you will be able to learn how to:
Create various types of variables and manipulate with the values
Understand Arrays and Hash Tables and how to use them
Understand how variables, arrays, and hash tables could be helpful for building basic
scripts
Prerequisites
To complete this lab, you need:
Windows 2008 and Windows 7 workstation logged onto with administrator credentials
Microsoft Confidential
Page 140 of 361
Scenario
The Windows PowerShell variable provider allows you to create, add, and delete variables.
First, let us understand what a variable is. A variable, as the name suggests, is something
whose value can vary.
Variables are primarily used for two reasons:
1. To hold some value or data in memory
2. To hold the output, which is a result of an expression
Variables can store information about different types such as string, integer, and Boolean.
The various types will be discussed later in this lesson.
In the exercise below, the following operations will be demonstrated using variables:
Variable assignment
Variable expansion
Variable related Cmdlets
You can use the New-Variable built in Cmdlet as well, to create a new variable. When
using the New-Variable Cmdlet, you do not need to add a $ sign before the variable name.
2. To create a variable using the New-Variable Cmdlet, type the following command:
PS C:\> New-Variable Results2 –value “We won again!”
Microsoft Confidential
Page 141 of 361
3. Write an expression that performs a compare operation and stores the result of the
operation inside a variable.
The expression will be evaluated to either True or False. The expression would be as
follows:
PS C:\> $a = 5 Creating a new variable and assigning the value of 5.
PS C:\> $b = 6 Creating a new variable and assigning the value of 6.
-gt in Windows PowerShell is a comparison operator for "Greater Than". In this case, the
expression evaluates to true.
The result will be stored in the variable $c. Note the “Type” of the variable, $c.
PS C:\> $c.GetType()
PS C:\> $a.gettype()
A "Type" is what defines the kind of information or value that can be stored in a variable.
Note: A variable name can also have spaces in between however; remember to
enclose the variable name inside a curly brace.
Automatic Variables
Although you can choose a name of your choice for a variable, there are certain special
variables that are predefined in PowerShell.
Microsoft Confidential
Page 142 of 361
The following are some of the automatic variables that are predefined in Windows
PowerShell. These variable names are reserved.
$Args Stores values of parameters passed to a function
$Error Stores information about the error object when an error has occurred during
any script execution
$PsHome Home directory where the PowerShell is installed
$Home Home directory of the user
$True Check for Boolean Value of True
$False Check for Boolean Value of False
Note: For a complete list of automatic variable, refer the Online Help.
Variable Expansion
Quotes have a special meaning when used with variables.
Consider the following example:
PS C:\> $First = “Hello”
PS C:\> $Statement1 = “$First World”
PS C:\> $Statement1
Hello World
The output stored in the variable $Stament1 will be Hello World. This is because, when you
use double quotes, Windows PowerShell will expand the variable name with its value.
In the example, you can see that the output is Hello World. This is because, Windows
PowerShell substitutes $First with its value, which is Hello.
On the other hand, if you assign the values within single quotes, Windows PowerShell takes
that as a literal value and does not substitute the value. Consider the following example,
PS C:\> $First = ”Hello”
PS C:\> $Statement1 = ‘$First World’
PS C:\> $Statement1
$First World
You can see in this example that the value of $First is not inserted into $Statement1
We learnt about variables in this section however, there might be situations where we need to
constant value. We can define a constant using Set-Variable Cmdlet.
Microsoft Confidential
Page 143 of 361
Task 3: Expressions
Windows PowerShell executes the command depending on the command input. If a native
Windows command was typed, PowerShell will execute the command in a way similar to
how Windows would execute in a CMD command shell.
Similarly, if you write a mathematical or a comparison expression in the PowerShell console,
it will process accordingly.
1. Type the following command in the PowerShell console:
PS C:\> ipconfig.exe
Windows IP Configuration
Connection-specific DNS Suffix . :
IPv4 Address. . . . . . . . . . . : 192.168.1.1
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 0.0.0.0
6*5
Microsoft Confidential
Page 144 of 361
30
After processing Write-Host, PowerShell encounters the “(“ which causes it to switch to
expression mode parsing. In this expression mode, it actually evaluates the mathematical
expression of 6*5 and the output is 30.
4. The dollar sign is another one of the common characters that can cause PowerShell to
enter expression mode parsing.
$int = 5 + 5
$int
You can see now that instead of treating the line of text as a command, PowerShell sees
the dollar sign and knows that this is an expression to be evaluated, one which assigns the
value of 5+5 into the variable “int”. On the second line, the evaluation is simply to
retrieve the variable, which causes PowerShell to output that variable to the pipeline.
5. You can also force PowerShell into argument mode on a given expression. Enter the
following commands:
$cmd = “get-command”
$cmd
We are simply using expression parsing mode and assigning a string into a variable.
Note that the “get-command” cmdlet is not actually executing, this is merely a text
assignment.
6. Using the ampersand, also known as the “call operator”, we can now force the previous
expression to be evaluated in argument mode instead.
&$cmd
This time the output is the same as if you directly executed the “get-command” cmdlet.
7. Script blocks are another example where PowerShell changes between parsing modes.
Execute the following code:
{ get-command –verb get }
This simply defines a script block, but does not execute it.
8. You can execute the code by putting the call operator in front of it:
& {get-command -Verb get}
Microsoft Confidential
Page 145 of 361
Scenario
In PowerShell, you can create and delete objects for various purposes. In those objects, you
can store data for performing some operations. Before you can store data, you may define the
kind of data to be stored in that object. The kind of information that can be stored in an object
is defined by its "Type".
Let us look at a few examples to understand this in detail.
In the exercise that follows, the use of different “Types” will be demonstrated.
Number types
String types
Expandable strings
Literal strings
Here-strings
Other types
2. Here, you create a new variable and store a value of 9 in it. Now, let us see the type of
variable.
3. To find the type of variable, use the GetType() method.
PS C:\>$a.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
Microsoft Confidential
Page 146 of 361
4. Note the name, Int32. To hold the value, 9, you created an instance of "Type" of Int32
object. An Int32 object represents a 32-bit integer.
5. Change the value of the variable from an integer to a floating point.
PS C:\> $a = 4.5
PS C:\> $a.gettype()
Note the Name property. It changed from Int32 to Double. An instance of "Type" of
Double object represents a floating-point number.
6. Assign a larger value to the same variable.
PS C:\> $a =8000000000
PS C:\> $a.gettype()
PS C:\> $a.gettype()
PS C:\> $b = 2
PS C:\> $c
True
PS C:\> $c.gettype()
Microsoft Confidential
Page 147 of 361
In the example above, you created two variables initially, assigned values to it and then did a
compare operation. To store the result of the compare operation, you created a third variable
and you can see that the "Type" is Boolean.
Expandable Strings
String expansion is a very important functionality in Windows PowerShell. Consider an
example to understand this behavior.
In the following example, you will understand the significance of quotes with variables:
1. Create a new variable name and assign the string value Bob in double quotes.
2. Use the same variable with a statement enclosed in double quotes.
PS C:\> $name = "Bob"
You can notice that when the string was in double quotes, you substituted the variable
$name with its value. This behavior is called string expansion.
3. Now, try the same using single quotes.
When the statement is enclosed with a Single quote, we see that the variable is not
substituted with its value.
PS C:\> 'Hi $name, Welcome to the PowerShell workshop'
Hi $name, Welcome to the PowerShell workshop
Literal Strings
4. To assign a string value to the variable, type the following command:
PS C:\> $a = "Welcome to the world of PowerShell!"
PS C:\> $a
Welcome to the world of PowerShell!
PS C:\> $a.GetType()
Microsoft Confidential
Page 148 of 361
5. To store a string value in a variable, use either a single quote or a double quote.
PS C:\> $a = "Welcome to the world of PowerShell!"
PS C:\> $a
Welcome to the world of PowerShell!
PS C:\> $a
Welcome to the world of PowerShell!
In this case, both yield the same results for a simple assignment.
Here Strings
A Here string is used to place a sequence of strings the way they are, without any additional
formatting.
Consider an example.
6. Create another variable and assign the string value exactly as shown below.
PS C:\> $NewString = "Hello and how are you?"
PS C:\> $NewString
Hello and how are you?
PS C:\> $ComplicatedString = ""Good Morning!, how are you?", would you like to
have a cup of tea or coffee?""
Unexpected token 'Good' in expression or statement.
At line:1 char:28
+ $ComplicatedString = ""Good <<<< Morning!, how are you?", would you like to
have a cup of tea or coffee?""
+ CategoryInfo : ParserError: (Good:String) [],
ParentContainsErrorRecordException
Microsoft Confidential
Page 149 of 361
+ FullyQualifiedErrorId : UnexpectedToken
PS C:\> $ComplicatedString = "Good`Morning!, how are you?", would you like to have
a cup of tea or coffee?"
Missing expression after ','.
At line:1 char:52
+ $ComplicatedString = "Good`Morning!, how are you?", <<<< would you like to have
a cup of tea or coffee?"
+ CategoryInfo : ParserError: (,:String) [],
ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingExpressionAfterToken
You can make this work by adding a few correct quotes and braces, but it is time
consuming. In such a case, Here string is useful.
8. In PowerShell, type the following command:
PS C:\> $ComplicatedString = @”
>> Good Morning!How are you?, would you like to have a cup of tea or a coffee?
>> "@
>>
PS C:\> $ComplicatedString
Good Morning!How are you?, would you like to have a cup of tea or a coffee?
PS C:\>
The string included between the start and the end of the Here string is displayed as it is.
Windows PowerShell does not parse any quotes or braces inside a Here string. Hence, the
string is stored without any errors.
Other Types
You looked at some of the basic primitive number and string types. However, Windows
PowerShell has more types available in it. The following table from TechNet shows the
various types.
Data Type Alias Type Description .Net Framework Type
[int] 32-bit signed integer System.int32
[long] 64-bit signed integer System.int64
[string] Fixed-length string of Unicode System.String
characters
[char] Unicode 16-bit character System.char
[bool] True/false value System.Boolean
[byte] 8-bit unsigned integer System.byte
[double] Double-precision 64-bit floating System.Double
point number
[decimal] 128-bit decimal value System.Decimal
[single] Single-precision 32-bit floating System.Single
point number
[array] Array of values System.Array
[xml] Xmldocument object System.Xml.XmlDocument
Microsoft Confidential
Page 150 of 361
The above table contains what are called data type aliases. These are used as a shortcut
instead of typing the whole .NET framework types when in PowerShell. There are many
more data type aliases available. However, the table above does cover most of the common
alias that you will encounter. It is also possible to create your own data type aliases but this
will not be covered here.
A common use of the datatype aliases is to use them to qualify either data as a certain type or
to type constrain a variable.
Normally in powershell you are not too concerned with the types of a variable or data. This is
due to the type adaption system that powershell uses which converts the type when needed.
However, there are some circumstances that might require the types to be qualified. To do
this with PowerShell, you use the data type aliases.
Data qualification
Using the data type aliases on the right hand side of the assignment operator allows for the
data to be qualified, or cast as a specific type.
1. Type the following in the PowerShell console to create a variable
$a = 77
Microsoft Confidential
Page 151 of 361
You will see that you have an int32. This is due to qualifying, or casting the data as a number.
However, the variable can still be set to a string or any other type as the variable has not been
type constrained.
7. Type the following to set $a to a string
$a = “See I can still be a string”
Type constraining
As well as being able to qualify data as a specific type, it is possible to also constrain a
variable to be a specific type. This is done by using the data type alias on the left hand side of
the assignment operator. This means that the variable will only be able to contain data of that
specific type. If you try to assign a different type to that variable it will fail.
You will see that you have an int3 even though a string of “77” was assigned .
5. Type the following to assigned a string to the variable
$a = “this will not work”
You will now see that you get an error from PowerShell. This is because the string “this will
not work” cannot be converted to an int32. This is because we can only store numbers in the
variable due to the type constraint.
6. Type the following to assign another number to the variable
$a=42
Microsoft Confidential
Page 152 of 361
You will see that you have a string. If you try to now assign a number this will now fail.
9. Type the following to assign an int32 to $a
$a = 42
You will now see that this succeeds because converting an integer to a string is allowed.
10. You can also effectively remove the constraint from a variable by making it of type
object. Type the following to qualify the variable as type object
[object]$a = 42
Microsoft Confidential
Page 153 of 361
Scenario
In the previous exercise, you learnt about the use of variables and the type fundamentals in
PowerShell. Let us continue to explore the functionality and use of arrays in this module.
An array object contains a collection of elements of the same type. For example, an array of
integers or string.
While evaluating any expression, the output can be either a single object or a collection of
objects.
To store the result of all services on a computer, you create an array.
The following is an illustration of a simple one-dimensional array.
PS C:\> $NewArray.Gettype()
Microsoft Confidential
Page 154 of 361
PS C:\> $Numbers
1
2
3
4
5
PS C:\> $Numbers.gettype()
4. Use the Get-Service Cmdlet to get a list of all services running on a computer and store
the output in $service as an array.
PS C:\> $service = get-service
PS C:\> $service
PS C:\>
PS C:\> $numbers.count
10
Microsoft Confidential
Page 155 of 361
The count property of array tells us how many elements are present in an Array.
2. To add an element and assign a value, type the following command:
PS C:\> $numbers += 11
PS C:\> $numbers
1
2
3
4
5
6
7
8
9
10
11
PS C:\> $numbers += 12
PS C:\> $numbers.Count
12
PS C:\>PS C:\>
The count of the array has increased since you added two elements.
1 2 3 4 5 6 7 8 9 10
The array holds values for 10 elements. To find the value in the first element, which is 1,
refer the index number 0.
In the following example, a variable named $numbers stores the numbers 1 to 10.
Take a count of how many elements you have in the array. Modify the value of the first
element in the array.
#Create an array and assign values to elements.
PS C:\> $numbers = @(1,2,3,4,5,6,7,8,9,10)
PS C:\> $numbers.count
10
PS C:\> $numbers[0]= 11
PS C:\> $numbers
11
2
3
4
5
6
Microsoft Confidential
Page 156 of 361
7
8
9
10
PS C:\>
In an array, you can use the index number to refer to individual elements.
$a[0] This will display the value of the 1st element.
$a[1] This will display the value of the 2nd element.
$a[-1] This will display the value of the last element in
array.
$a[-2] This will display the value of the second last
element in array.
Microsoft Confidential
Page 157 of 361
Scenario
Hash table is a kind of array where we can store the values in a key-value pair.
Hash tables are used when we need to store information in the form of a dictionary array and
then access the value of an element using a corresponding label name.
The following is an example of an array representing the ID of employees within an
organization:
Dave 183
Roy 478
Alice 671
In this module, the following operations for hash tables will be discussed.
Creating hash tables
Adding to hash tables
Hash table addressing
$Numbers.GetType()
Let us look at a hash table, which contains employee name and ID.
1. In the PowerShell console, type the following command to create a hash table.
$a = @{"Dave"=123; "Roy"=478; "Alice"=671}
$a
Name Value
---- -----
Dave 183
Microsoft Confidential
Page 158 of 361
Roy 478
Alice 671
Note: The order of your keys/value pairs may show up sorted differently than the
exercises below, this is normal behavior because hash tables are not ordered.
1. In the PowerShell console, type the following command to create a hash table:
$ComputerType = @{"Type1"="Desktop";"Type2"="Server";"Type3"="Laptop"}
$ComputerType
Name Value
---- -----
Type1 Desktop
Type2 Server
Type3 Laptop
$ComputerType
Name Value
---- -----
Type1 Desktop
Type2 Server
Type3 Laptop
Type4 TabletPC
3. In the PowerShell console, type the following command to add a new entry to a hash
table:
$computertype.Type5=”Slate”
Name Value
---- -----
Type1 Desktop
Type2 Server
Type3 Laptop
Type4 TabletPC
Type5 Slate
4. In the PowerShell console, type the following command to change the value of an
existing key:
$ComputerType[“Type4”] =”Netbook”
$ComputerType
Microsoft Confidential
Page 159 of 361
Name Value
---- -----
Type1 Desktop
Type2 Server
Type3 Laptop
Type4 Netbook
Type5 Slate
$a
Name Value
---- -----
Dave 183
Roy 478
Alice 671
$a.Roy
478
$a.Alice
671
According to the definition, this table contains a Key-Value pair. Every key will have an
associated value to it and you can address the value by using a dot reference to its key.
Microsoft Confidential
Page 160 of 361
Scenario
Like every other scripting and programming environment, Windows PowerShell offers
variety of methods from where an input can be passed for a command to be executed as well
as to display the results.
The Windows PowerShell console host is where the command you type is by default, used to
take the user input and to display the output.
First, let us look at the input mechanisms in Windows PowerShell.
The following is a sample script that prompts a user to enter a valid path. After the path is
entered, scan the directory to get only the files inside that directory.
Console Input
============
Script code:
============
$Path = Read-Host "Please enter a valid path"
In this code, a Cmdlet, Read-Host that prompts a user for an input is used. Based on the input,
the script will be processed further.
While using the Cmdlet is one way of passing an Input to PowerShell, the PowerShell
console Host also takes a user input and processes the commands.
Console Output
You might have noticed that whenever you type a command in the PowerShell console, you
see the output in the command window.
Microsoft Confidential
Page 161 of 361
This is because of the Out-Default Cmdlet that is executed after every Cmdlet. Therefore, in
the PowerShell console, whenever you execute a command, Get-Service, PowerShell is
actually executing the command Get-Service | Out-Default.
Out-Default will send the output to Out-Host and then the output is displayed on the host
window.
Additional options to specify output to a specific object:
Out-File Will send an output to a file
Out-Printer Will send an output to a printer
Out-Host Default output window
Out-Grid Display the output in a Grid view
Write-Host Writes customized output to a host
Write-Output Sends the specified objects to the next command
in the pipeline.
If the command is the last command in the
pipeline, the objects are displayed in the console.
Tee-Object Saves command output in a file or variable, and
displays it in the console
Microsoft Confidential
Page 162 of 361
Scenario
Windows PowerShell adds functionalities to manage files and folders on a local as well as a
remote computer.
Administrators can perform a variety of operations for files and folder management such as
create, delete, rename, copy, and move.
You can see that the result is True as you know that the folder does exist.
2. Type the following command to verify the existence of another folder:
test-path C:\Windows\system32\anotherwindows
False
As expected, the result is false as there is no folder with the name anotherwindows.
3. Type the following command to see how you can implement the simple test as an
important check in script:
$Fileinfo = Test-Path C:\Windows\System32\drivers\ntfs.sys
if ($Fileinfo -eq "True") {Write-Host "File Exists"}
File Exists
When this is executed, observe the output. You can also add another condition to write
File Does not exist, if it does not.
PowerShell also allows copying or moving files from one location to another. In the
following example, you will copy a file from C:\ to D:\ using the following command.
Copy-Item C:\pshell\part1\lesson5\setup.log C:\pshell\part1\lesson5\newsetup.log
4. Run the following Cmdlet to move the file from one location to another.
Move-Item C:\pshell\part1\lesson5\setup.log c:\temp -force
You can also delete, or rename files using the Delete-Item, or Rename-Item Cmdlets.
Microsoft Confidential
Page 163 of 361
Alternatively, you can use these methods on a file or directory object to copy, move, or
delete.
$file = Get-Item C:\pshell\part1\lesson5\setup.log
$file | gm –membertype method
TypeName: System.IO.FileInfo
File.CopyTo(“C:\temp\Newlog.txt”)
[InstallShield Silent]
Version=v7.00
File=Log File
[ResponseResult]
ResultCode=0
[Application]
Name=Integrated Camera Driver Installer Package Ver.1.1.0.42
Version=1.1.0.42
Company=RICOH
Lang=0009
VersionInfo
2. You can also clear the contents of file using the Clear-Content Cmdlet as follows:
Microsoft Confidential
Page 164 of 361
Clear-Content C:\pshell\part1\lesson5\setup.log
2. Run the Get-Content Cmdlet, to verify the content of the text file.
Get-Content C:\pshell\part1\lesson5\test1.txt
Hello
3. You may want to write entire output of a Cmdlet to a file. For example, the status of all
the services running on a computer, list of all the running process etc.
4. This can be achieved using the Out-File Cmdlet as follows:
Get-Service | Where-Object {$_.status -eq "Running"} | Out-File `
-FilePath "C:\pshell\part1\lesson5\Services.txt"
Get-Content C:\pshell\part1\lesson5\Services.txt
Name Status
Appinfo Running
Microsoft Confidential
Page 165 of 361
AudioEndpointBuilder Running
AudioSrv Running
BDESVC Running
BFE Running
BITS Running
Bthserv Running
btwdins Running
CcmExec Running
The first Cmdlet gets a list of all the services of the system.
Then we pipe that output and take a look at the status property of each object to match if
it is "Running".
Then, we use the ConvertTo-HTML Cmdlet to covert the output.
The end part, Set-Content Cmdlet writes the content to the file.
PowerShell also adds the flexibility to export the content to a CSV file. We can use the
Export-CSV Cmdlet to export the output to a CSV file
2. Consider another example.
Get-Service | Where-Object {$_.status -eq "Running"} | Export-CSV `
C:\pshell\part1\lesson5\Services.csv
notepad c:\pshell\part1\lesson5\services.csv
The code above exports the output to a CSV file and loads it.
3. One last example deals with saving content in a much more rich format: XML.
Get-Service | Where-Object {$_.status -eq "Running"} | Export-clixml `
C:\pshell\part1\lesson5\Services.xml
Invoke-item C:\pshell\part1\lesson5\Services.xml
Microsoft Confidential
Page 166 of 361
Scenario
It is common for an administrator, writing a script to encounter an error during the execution.
PowerShell provides a rich set of inbuilt objects and mechanisms to understand the error
details and then take the necessary corrective actions.
At line:1 char:12
+ Get-Process <<<< invisibleapp.exe
+ CategoryInfo : ObjectNotFound: (invisibleapp.exe:String) [Get-
Process], ProcessCommandException
+ FullyQualifiedErrorId :
NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
The error on the console host can be viewed. In Windows PowerShell, there is an Error object
of type, System.Management.Automation.ErrorRecord.
The automatic variable $Error contains information about the most recent errors.
$error
Get-Process : Cannot find a process with the name "invisibleapp.exe". Verify the
process name and call the Cmdlet again
At line:1 char:12
+ Get-Process <<<< invisibleapp.exe
+ CategoryInfo : ObjectNotFound: (invisibleapp.exe:String) [Get-
Process], ProcessCommandException
+ FullyQualifiedErrorId :
NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Like other array objects, you can take a count of the errors currently stored in the error object.
$error.count
1
Microsoft Confidential
Page 167 of 361
Since this is implemented as an array, use the traditional method to refer to index 0 for the
value of the first element.
Below you can see some examples of what errors may look like, but your environment will
likely be very different.
$error[0]
Get-Process: Cannot find a process with the name "invisibleapp.exe". Verify the
process name and call the Cmdlet again
At line:1 char:12
+ Get-Process <<<< invisibleapp.exe
+ CategoryInfo : ObjectNotFound: (invisibleapp.exe:String) [Get-
Process], ProcessCommandException
+ FullyQualifiedErrorId :
NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
$error[1]
The term 'lastexistcode' is not recognized as the name of a Cmdlet, function,
script file, or operable program. Check t
he spelling of the name, or if a path was included, verify that the path is
correct and try again.
At line:1 char:14
+ lastexistcode <<<<
+ CategoryInfo : ObjectNotFound: (lastexistcode:String) [],
CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
$error[2]
Get-Item : A positional parameter cannot be found that accepts argument 'Exit'.
At line:1 char:9
+ Get-Item <<<< c:\doentexist.txt Exit 123
+ CategoryInfo : InvalidArgument: (:) [Get-Item],
ParameterBindingException
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetItemCommand
$error[3]
Get-Item : Cannot find path 'C:\doentexist.txt' because it does not exist.
At line:1 char:9
+ Get-Item <<<< c:\doentexist.txt
+ CategoryInfo : ObjectNotFound: (C:\doentexist.txt:String) [Get-
Item], ItemNotFoundException
+ FullyQualifiedErrorId :
PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
By default, you can store up to 256 errors in the $Error object. This is implemented using the
$MaximumErrorCount variable.
However, the value for the variable in the example can be changed.
It is also possible to clear the error variable. You can do this by using the clear method on the
error variable. This is a good idea to use when scripting with PowerShell. This enables you to
focus only on the errors that your scripts has generated, not errors that might have been
produced outside of the current script.
Microsoft Confidential
Page 168 of 361
Errprocess
Get-Process : Cannot find a process with the process identifier 112.
At line:1 char:12
+ get-process <<<< -id 112 -ErrorVariable Errprocess
+ CategoryInfo : ObjectNotFound: (112:Int32) [Get-Process],
ProcessCommandException
+ FullyQualifiedErrorId :
NoProcessFoundForGivenId,Microsoft.PowerShell.Commands.GetProcessCommand
$LastExitCode
0
Here, the result of execution of the code was successful and hence, the last exit code is 0.
There can be a user defined exit code.
2. Type the following command to ping a non-existent IP address and observe the error.
ping 127.0.0.900
Ping request could not find host 127.0.0.900. Please check the name and try again.
$LastExitCode
1
Microsoft Confidential
Page 169 of 361
$?
False
Windows PowerShell allows specifying how it may respond to non-terminating errors. The
preference is defined in the $ErrorActionPreference variable.
$ErrorActionPreference
Continue
Currently, the preference is set to Continue and will therefore display the error and continue
with the script execution.
The other possible values for this variable are:
SilentlyContinue
When the preference is set to SilentlyContinue, the flow of execution of script continues even
when an error is encountered and it does not display the error on the host.
1. In the powershell console type the following
$erroractionpreference = "SilentlyContinue”
2. Type the following command which will fail, but will not display any output.
Get-item fakefile
Inquire
Prompts for a user action when an error is encountered.
Stop
Halts the script execution.
Microsoft Confidential
Page 170 of 361
You will note that the above does not display an error as per the previous command did.
Microsoft Confidential
Page 171 of 361
Pre-requisites
The lab requires a Windows 7 client running in a domain environment.
Microsoft Confidential
Page 172 of 361
PS C:\> $z.GetType()
Microsoft Confidential
Page 173 of 361
10. In the PowerShell console, type the following command to view the output stored in $c:
PS C:\> $c
Good Morning, How are you?
11. Verify the results. This addition operation is also called String Concatenation.
You will now use the variable to store a collection of objects.
12. In the PowerShell console, type the following command to get a list of all running
processes on a system:
PS C:\> $Process = Get-Process
Close all instances of notepad except one. If notepad is not running, start it.
14. On the next line, type the following command to find an instance of a running process
and store the output in $ProcessNotepad variable:
PS C:\> $ProcessNotepad = Get-Process Notepad
16. Type the following commands to view the properties of the object stored in
$ProcessNotepad:
PS C:\> $ProcessNotepad.Threads
PS C:\> $ProcessNotepad.CPU
PS C:\> $ProcessNotepad.Handles
PS C:\> $ProcessNotepad.Path
Microsoft Confidential
Page 174 of 361
2. In the PowerShell console, type the following command to access the first element in the
array, and view the output:
PS C:\> $Currency[0]
3. In the PowerShell console, type the following command to access the last element in the
array, and view the output:
PS C:\> $Currency[-1]
4. In the PowerShell console, type the following command to add a new element to an
existing array:
PS C:\> $Currency += "Yen"
8. In the PowerShell console, type the following command to store the first 10 application
event logs:
PS C:\> $logs = get-eventlog application | Select-Object -First 10
Microsoft Confidential
Page 175 of 361
9. In the PowerShell console, type the following command to view the properties and
methods for the first object of an array:
PS C:\> $logs[0] | Get-Member
10. In the PowerShell console, type the following command to identify the machine name on
which the event was generated:
PS C:\> $logs[0].MachineName
11. In the PowerShell console, type the following command to find the description:
PS C:\> $logs[0].Message
Make sure that quotes are added for string values or else you may encounter certain errors.
2. In the PowerShell console, type the following command.
PS C:\> $ArrayCombined = $Array1 + $Array2
Microsoft Confidential
Page 176 of 361
4. In the PowerShell console, type the following command to add a new key-value to this
table:
PS C:\> $NewHashTable["Telephone"] = "98052-7329"
You added a new key. However, the value added is incorrect. The value is not the
telephone number, but the PIN.
5. In the PowerShell console, type the following command to modify and assign the correct
value:
PS C:\> $NewHashTable["Telephone"] = "425-882-8080"
8. In the PowerShell console, type the following command to view the output in a list
format:
PS C:\> $NewHashTable | FL *
Microsoft Confidential
Page 177 of 361
You can create a hash table to store a specific type of values (integer, string) by prefixing its
type before the name. Use the same method for creating arrays of specific type.
9. In the PowerShell console, type the following command to sort the output by value:
PS C:\> $NewHashTable.GetEnumerator() | Sort Value
10. In the PowerShell console, type the following command to sort the output by name:
PS C:\> $NewHashTable.GetEnumerator() | Sort Name
Microsoft Confidential
Page 178 of 361
Name CPU
---- ---
notepad 0.3744024
notepad 0.0936006
notepad 0.0780005
notepad 0.0936006
4. If you want to find for how long each instance of Notepad is running, you can use a
calculated object property to find out the values.
5. In the PowerShell console, type the following command:
Microsoft Confidential
Page 179 of 361
In the first part of the script, you can notice that to create a calculated property a hash
table is created using @{}. Later, the expression is specified to provide the value for
TotalRunningTime property.
Create a hash table and a calculated object property using the Select-Object Cmdlet.
6. In the PowerShell console, type the following command:
PS C:\> get-process
Microsoft Confidential
Page 180 of 361
Microsoft Confidential
Page 181 of 361
Objectives
The objectives for this lesson are:
To define what constitutes a script and basic script elements such as:
Comments (#)
White space
Line terminators (newline, semicolon)
Script arguments
To explain how to execute a script and the security features that are applicable to running
scripts, including:
The execution policy and group policy objects
Script signing
To explain PowerShell language iteration statements such as:
Do While and Do Until
For and ForEach
While
To explain PowerShell language flow control statements, such as:
Break and continue
Return and Exit
To explain other statements that are commonly used in scripts, including:
Labeled statements
If
Switch
To describe functions and their basic features, including:
Param-blocks and Function-parameter-declaration
Argument processing
The [switch] type constraint
Microsoft Confidential
Page 182 of 361
Prerequisites
A Windows 7 workstation logged onto with administrator credentials.
Microsoft Confidential
Page 183 of 361
Scenario
A script is a collection of commands that are stored in a file with a .ps1 filename extension.
Scripts are not explicitly named within the file; instead, they take their name from the file
name.
Restricted Permits individual commands but will not run scripts.
(default)
All Signed Scripts can run.
Requires that all scripts be signed by a trusted publisher, including scripts that
you write on the local computer
Prompts you before running scripts from publishers that you have not yet
classified as trusted or untrusted
Risks running unsigned scripts from sources other than the Internet and
signed, but malicious, scripts
Note: Type get-help about_signing at a PowerShell command prompt to
display insyntaxion related to signing scripts.
Remote-Signed Scripts can run.
Requires a digital signature from a trusted publisher on scripts that are
downloaded from the internet (including email and instant messaging
programs)
Unrestricted Unsigned scripts can run.
Warns the user before running scripts from the internet
Bypass Nothing is blocked and there are no warnings or prompts.
This execution policy is designed for configurations in which a Windows
PowerShell script is built into a larger application or for configurations in which
Windows PowerShell is the foundation for a program that has its own security
model
Undefined There is no execution policy set in the current scope
If the execution policy in all scopes is Undefined, the effective execution
policy is Restricted, which is the default execution policy
Microsoft Confidential
Page 184 of 361
PowerShell execution policies define the conditions under which PowerShell runs scripts.
The following policies can be configured:
2. In the PowerShell console, type the following command:
set-executionpolicy unrestricted
Note: Execution policies for the local computer and current user are stored in the
registry and therefore there is no need to set execution policies in a PowerShell profile.
2. Start your new script file by annotating the script using comments.
PowerShell treats comments as white space. White space is only used to separate tokens
in PowerShell; other than that, it is ignored for all purposes.
Microsoft Confidential
Page 185 of 361
The script 'Lesson_6_exercise_1.ps1' cannot be run because it contained a "#requires" statement at line 1 for
Windows PowerShell version 3.0. The version required by the script does not match the currently running version
of Windows PowerShell version 2.0.
At line:1 char:15
+ .\ Lesson_6_exercise_1.ps1 <<<< + CategoryInfo : ResourceUnavailable: (lesson_6_exercise_1:String)
[], ScriptRequiresException + FullyQualifiedErrorId : ScriptRequiresUnmatchedPSVersion
6. Change the comment in the script file from #requires -version 3 to #requires -version 2.
#requires -version 2
Microsoft Confidential
Page 186 of 361
Microsoft Confidential
Page 187 of 361
Note: This addition to the Windows PATH environment variable will be lost when
the PowerShell session is closed. The command can be added to a PowerShell Profile
(this topic is covered later in this course) if required to persist between sessions.
D. Specify the full path and filename for the script file.
E. If the path and/or the script filename contain any spaces, enclose the command with
single or double quotes and prepend with an ampersand.
4. PowerShell scripts can also be run external to the PowerShell command shell. A common
practical use for this is creating scheduled tasks that run PowerShell scripts.
5. Click Start > Run and type the following command:
powershell.exe -noexit -file c:\Pshell\part1\Lesson6\lesson_6_exercise_1.ps1 `
-executionpolicy bypass
Note: The ExecutionPolicy Bypass setting allows scripts to run regardless of whether
the current execution policy allows the running of scripts or not.
Microsoft Confidential
Page 188 of 361
#requires -Version 2
<#
Author:
Date:
#>
Microsoft Confidential
Page 189 of 361
Scenario
PowerShell iteration statements provide the basic logic needed to make programmatic
decisions within a script.
PowerShell scripts use several familiar programming statements for iteration (i.e., looping
and branching).
The syntax for these statements is in the form of a script block. A script block in PowerShell
is always opened and closed with braces and contains the code to be executed if a previous
condition, defined within smooth parentheses, evaluates to true.
Iteration statements are used to loop through and execute code multiple times. Iteration is a
method to reduce the amount of code that is required to achieve a desired outcome.
Microsoft Confidential
Page 190 of 361
2. Remove all commands from the file, keeping only the commented text.
3. Modify the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
write-host "starting do while example..."
$i = 1
do
{
write-host “iteration number $i”
}
while (++$i -le 5)
In the do while example, PowerShell will loop through and execute the code as long as
the value of $i is less than or equal to 5.
In the do until example, PowerShell will loop through the code until the value of $i is
greater than or equal to 5.
Microsoft Confidential
Page 191 of 361
This is useful when you want to run the same code for a group of objects, but you do not need
to know how many objects there are in the loop. You just need to execute the same code for
each member of the collection.
The syntax of the foreach statement is as follows:
foreach (<temp variable> in <collection variable>){<code to execute>}
The for iteration statement is different from the foreach because, it can be used to loop a
certain number of passes through the code.
This is useful if only a certain number of passes is required. Another benefit of this statement
is that you have an automatic counter for the current pass of the loop.
The syntax of the for statement is as follows:
for (<initial variable> ; Boolean loop condition; counter handling){<code to execute>}
Let us look at an example of these two iteration statements.
1. In the command prompt, type the following to open the script previously created in
Notepad:
notepad C:\Pshell\part1\Lesson6\lesson_6_exercise_1.ps1
2. Remove all commands from the file, keeping only the commented text.
3. Modify the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
Microsoft Confidential
Page 192 of 361
In the foreach example, PowerShell will execute the code (i.e., write-host “iteration
number $t” in the example) once for each item in the variable $i.
In the for example, PowerShell will execute the code (i.e. write-host “iteration number $i”
in the example) as long as the variable $i is greater than or equal to 1.
2. Remove all commands from the file, keeping only the commented text.
3. Modify the file to look like this:
write-host "starting while example..."
$i = 1
while ($i -le 5)
{
write-host “iteration number $i”
++$i
}
4. Click File > Save As, and type “C:\Pshell\part1\Lesson6\Exercise_6_2c.ps1” in the file
name box.
5. In the command prompt, type the following to run the script:
C:\Pshell\part1\Lesson6\Exercise_6_2c.ps1
In the while example, PowerShell will execute the code (i.e., write-host “iteration
number $i”;++$i in the example) as long as the variable $i is less than or equal to 5.
Microsoft Confidential
Page 193 of 361
Scenario
As the name suggests flow control statements are used to control the flow of code through a
function, loop or script.
2. Remove all commands from the file, keeping only the commented text.
3. Modify the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
Microsoft Confidential
Page 194 of 361
}
$counter
}
In the break example, the code would normally cause an infinite loop because the while
statement has been set to $true. However, the break keyword is called once the counter
variable is greater or equal to 3 and therefore, the loop stops.
In the continue example, the code shows a foreach loop that loops over the numbers from
1 to 10. The range operator sends a stream of numbers to the if statement, where the
modulus operator determines whether the current number is exactly divisible by 2 (i.e., an
even number). The continue operator allows the loop to re-iterate if the result is $false
(i.e., not an even number).
2. Remove all commands from the file, keeping only the commented text.
3. Modify the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
Microsoft Confidential
Page 195 of 361
function Return-Example
{
write-host "starting return example..."
$i = 1
while ($i -le 5)
{
write-host “iteration number $i”
++$i
if ($i –eq 3)
{
return $i
}
}
}
$ReturnValue = Return-Example
Write-Host "Value returned: $ReturnValue"
function Exit-Example
{
write-host "starting exit example..."
$i = 1
while ($i -le 5)
{
write-host “iteration number $i”
++$i
if($i -eq 3)
{
Exit $i
}
}
}
Exit-Example
Write-Host “Exit code: $LastExitCode”
In the return statement example, PowerShell will execute the code (i.e. write-host
“iteration number $i”;++$i) as long as the variable $i is less than or equal to 5. However,
once the variable $i reaches 3 the loop is interrupted by the if statement condition
evaluating to true. The return statement terminates the loop and returns the value of $i at
that point.
In the exit example, PowerShell will execute the code (i.e. write-host “iteration number
$i”;++$i) as long as the variable $i is less than or equal to 5. However, once the variable
$i reaches 3, the loop is interrupted by the if statement condition evaluating to true. The
exit statement then terminates the script and control is handed back to the host without
executing the last line in the script. You can access $LastExitCode to view the value will
be equal to 3.
Microsoft Confidential
Page 196 of 361
Scenario
This section covers other statements that are commonly used in PowerShell scripting.
Labeled statements
Statement labels allow you to explicitly refer to a statement by a name.
Consider an example of statement labels.
1. In the command prompt, type notepad
C:\Pshell\part1\Lesson6\Lesson_6_exercise_1.ps1to open the script previously created
in Notepad.
notepad C:\Pshell\part1\Lesson6\Lesson_6_exercise_1.ps1
2. Remove all commands from the file, keeping only the commented text.
3. Change the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
Microsoft Confidential
Page 197 of 361
In the labeled statement example, breaking out of an inner and an outer while loop by
using the label construct to name the first while loop is demonstrated. The nested while
loop breaks the outer loop from ever being executed (stopping the final Get-Date cmdlet,
which would have been called infinitely).
If Statement
The if statement in PowerShell is used to test for a particular condition in a Boolean statement.
The syntax of an if statement is as follows:
if (<value> operator <value>){<code to execute if true>}
elseif (<value> operator <value>){<code to execute if true>}
else{<code to execute if not true>}
Note that the elseif and else parts are optional in an if statement.
Consider an example of an if statement.
1. In the command prompt, type notepad
C:\Pshell\part1\Lesson6\Lesson_6_exercise_1.ps1to open the script previously created
in Notepad.
notepad C:\Pshell\part1\Lesson6\Lesson_6_exercise_1.ps1
2. Remove all commands from the file, keeping only the commented text.
3. Change the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
$fooditem = “Pumpkin”
Microsoft Confidential
Page 198 of 361
Switch Statement
The switch statement in PowerShell is similar to the Select Case statement in VBScript.
The switch statement is very useful when you want to test a value and run code based on a
match. The same action can be performed using a compounded if, elseif statement, but it is
more complex. In the case of a switch statement, you simply put the variable that you want to
test in the statement and then list the matches and the code to execute for each match.
Note that the default match is optional and will match anything that is not matched by any of
the other patterns.
The syntax of the switch statement is as follows:
Switch (<variable>)
{
<match 1> { <code to execute> }
<match 2> { <code to execute>}
<match n> { <code to execute> }
Default { <code to execute> }
}
Consider an example of the switch statement.
1. In the command prompt, type notepad
C:\Pshell\part1\Lesson6\Lesson_6_exercise_1.ps1to open the script previously created
in Notepad.
notepad C:\Pshell\part1\Lesson6\Lesson_6_exercise_1.ps1
2. Remove all commands from the file, keeping only the commented text.
3. Change the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
switch ("Monday")
{
Monday {"Oh no its monday. You have to work today."}
Tuesday {"Oh no its Tuesday. You have to work today."}
Wednesday {"Its hump day, halfway there."}
Thursday {"Its TGIF eve. You have to work today"}
Friday{"Thank goodness its Friday. Almost the weekend"}
default {"It must be the weekend. No work today, you have to be happy. Its
required"}
}
Microsoft Confidential
Page 199 of 361
In the switch example, the value “Monday” is tested for a match. A match is found and
the code in the statement block is executed resulting in the text “Oh no it’s Monday. You
have to work today.” being displayed on the console. Note that the code in the statement
block for the default match would be executed if a match is not found.
Microsoft Confidential
Page 200 of 361
Exercise 5: Functions
Objectives
In this lesson, we will:
Create a basic function
Create a function with a function-parameter-declaration
Create a function with a param-block
Explain the switch type constraint
Explain named blocks and function pipelines
Scenario
Almost all programming languages employ the concept of functions, which allow code to be
encapsulated and referenced by name. This reduces the complexity of the code and makes it
more sustainable.
One important thing to note is that PowerShell functions must be declared before they can be
used in a script. In contrast to the functions used in a VBScript, PowerShell functions are
generally put at the top of the script.
To create a function, use the keyword function, followed by a name of your choice and open
a new script block with a set of curly parenthesis {…}. In its most basic form, a function is a
named block of code to execute. All code within the script block will be executed each time
the function is called.
To call a function, simply state the name of the function as shown in the following example:
2. Remove all commands from the file, keeping only the commented text.
3. Change the file to look like this:
Microsoft Confidential
Page 201 of 361
#requires -version 2
<#
Author:
Date:
#>
function Sort-Process
{
get-process | foreach-object {
if ($_.cpu -lt 1)
{
write-host $_.name, $_.cpu -foregroundcolor green
}
elseif ($_.cpu -gt 5)
{
write-host $_.name, $_.cpu -foregroundcolor red
}
}
}
sort-process
The function above is a basic function and is simply a block of code to execute, similar to
a VBScript sub-routine.
2. Remove all commands from the file, keeping only the commented text.
3. Change the file to look like this:
#requires -version 2
<#
Microsoft Confidential
Page 202 of 361
Author:
Date:
#>
function wmiping($computername)
{
$query = "select * from win32_pingstatus where address = '" + $computername +
"'"
$wmi = get-wmiobject -query $query
write-host "pinging $computername ... "
if ($($wmi.statuscode) -eq $null)
{
$rtnvalue = $($wmi.PrimaryAddressResolutionStatus)
}
else {$rtnvalue = $($wmi.statuscode)}
return $rtnvalue
}
wmiping localhost
The function above returns the WMI status code for a pingstatus command that is
executed against the localhost. The function is called using the function name (i.e.
wmiping) and the input value (i.e., localhost).
In the above function $computername represents a ‘function-parameter-declaration’.
2. Remove all commands from the file, keeping only the commented text.
Microsoft Confidential
Page 203 of 361
wmiping
This function also returns the WMI status code for a pingstatus command that is executed
against the localhost. The function is again called using the function name (i.e., wmiping)
and the input value (i.e., localhost).
The $computername parameter in the function is similar to the previous example of a
function but this time we have defined attributes for the parameter. That is, ‘Mandatory’,
which is used to enforce specifying a value for the parameter and ‘ValueFromPipeline’,
which means that the parameter value can be obtained from the pipeline.
2. Remove all commands from the file, keeping only the commented text.
3. Change the file to look like this:
#requires -version 2
<#
Author:
Microsoft Confidential
Page 204 of 361
Date:
#>
function multiplier ([switch]$multiply,$val1,$val2)
{
if ($multiply)
{
$val1*$val2
}
else
{
write-host “The ‘multiply’ switch has not been activated.”
}
}
multiplier -multiply 2 4
Note that the switch can be specified anywhere in the list of parameters. For example,
‘multiplier -multiply 2 4’ is the same as ‘multiplier 2 -multiply 4’ is also the same as
‘multiplier 2 4 –multiply’.
2. Remove all commands from the file, keeping only the commented text
3. Modify the file to look like this:
#requires -version 2
<#
Author:
Date:
#>
function myservicecounter
{
begin
{
$counter=0
}
process
{
if($_.status -eq "running")
Microsoft Confidential
Page 205 of 361
{
“$($_.name) `t $($_.status)";$counter++
}
}
end
{
“`n$counter services running”
}
}
get-service | myservicecounter
Microsoft Confidential
Page 206 of 361
Exercise 6: Profiles
Objectives
In this lesson, we will:
Understand the different types of profiles
Understand how to view profile locations
Create a profile for the Current User
Scenario
The PowerShell host application ‘resets’ every time it exits. This means that all aliases,
functions, variables and so forth that we create are lost upon exit. A PowerShell Profile can
be created to make customizations persist between PowerShell host sessions.
The ability to create a Profile is a very useful feature of PowerShell. A profile is simply a
start-up script that runs every time PowerShell starts. Each line in the script is run and
applied to each instance of PowerShell, every time PowerShell is run. (This concept is very
similar to the autoexec.bat file for those who remember the old DOS days). The profile can
hold simple lines that create new functions and aliases, or hold very complex and powerful
pieces of code.
$Profile is a special variable that can be used to retrieve the location of the current user on the
current host’s profile. $Profile always exists, however, by default the actual profile does not
exist and must be created manually. Typing $Profile displays where your personal profile
should be stored. To create the profile simply make a note of the directory structure and file
name, and create a text file with that name in the appropriate place.
There are four types of standard profiles, listed in order of precedence here:
Current User, Current Host – this is the profile referenced by $profile. This profile
applies only to the current user, and is run every time PowerShell.exe is run.
Current User, All Hosts – this profile applies to the current user and all PowerShell
instances, regardless of the executable host that PowerShell is hosted within.
All Users, Current Host – this profile applies to all users, and is run every time
PowerShell.exe is run.
All Users, All Hosts – this profile applies to all users and all PowerShell instances,
regardless of the executable host that PowerShell is hosted within.
There are also two profiles that are specific to the Integrated Scripting Environment (ISE):
ISE – Current User, Current Host – this is similar to the Current User, Current Host
profile. It is run instead of the normal $profile file.
ISE – All Users, Current Host – this is similar to the All Users, Current Host profile.
Microsoft Confidential
Page 207 of 361
2. Type $Profile to return the Current User Current Host profile location.
$Profile
5. Type $Profile.AllUsersAllHosts to return the All Users All Hosts profile location.
$Profile.AllUsersAllHosts
3. Type the following in the profile file to customize the PowerShell prompt for the current
user in the current host:
function prompt{$env:computername + " " + (get-location) + "> "}
Microsoft Confidential
Page 208 of 361
Note: To start PowerShell without any profile the following command can be run:
powershell.exe –noprofile
Microsoft Confidential
Page 209 of 361
Scenario
It is a relatively common practice to create libraries of PowerShell code (such as script blocks,
functions, aliases, variables, etc.) that can be utilized on demand.
These are typically packaged into one or more library scripts that can then be dot sourced.
Dot source notation is essentially a method to make items from your script library apply to
the current scope, as opposed to only applying to a nested scope. For example a dot sourced
script that sets a variable will make that variable available to the current scope whereas the
variable would only be available to the nested script scope without dot sourcing.
The syntax to dot source a script is as follows:
. \myscript.ps1
Note there is a space between the dot and the backslash.
Microsoft Confidential
Page 210 of 361
notepad $profile
Note that the assigned value is returned and that the $a variable is therefore available in
the current scope.
13. Type dir variable to see a complete list of the variables that is available in the current
scope.
Dir variable:
Microsoft Confidential
Page 211 of 361
Prerequisites
The lab requires a Windows 7 client running in a domain environment.
Microsoft Confidential
Page 212 of 361
3. Click File > Save As, and type “C:\pshell\part1\lesson6\labs\top5cpu.ps1” in the file
name box.
4. In the PowerShell window, type the following to run the script:
C:\pshell\part1\lesson6\labs\top5cpu.ps1
Microsoft Confidential
Page 213 of 361
3. Click File > Save As, and type “C:\pshell\part1\lesson6\lab6\topxxcpu.ps1” in the file
name box.
4. In the command prompt, type the following to dot source the script:
. C:\pshell\part1\lesson6\labs\topxxcpu.ps1
Notice that the top five CPU utilizing processes are returned.
6. In the command prompt, type the following
topxxcpu 15.
Microsoft Confidential
Page 214 of 361
4. Type the following in the profile file to customize the PowerShell session for all users
using any PowerShell host on this computer.
write-host "Hello $env:username!`n" -foregroundcolor green
$docs=”$home\documents”
write-host “The `$DOCS variable provides access to your documents located at:
`n$docs`n” -foregroundcolor green
Microsoft Confidential
Page 215 of 361
3. Create a variable named $intFolders, and ensure that it holds the value of 10. The code to
do this is shown here.
$intFolders = 10
4. Create a variable named $intPad. Do not put anything in the variable yet:
$intPad
6. Use the New-Variable cmdlet to create a variable named strPrefix. Use the value
argument of the cmdlet to assign the value of "testFolder" to the variable. Use the option
argument to change $strPrefix to a constant:
New-Variable -Name strPrefix -Value "testFolder" -Option constant
7. Open a do … until statement. Include the opening curly bracket for the script block:
do {
9. Open the script block for the if statement. Assign the value of 0 to the variable $intPad:
{$intPad=0
Microsoft Confidential
Page 216 of 361
10. Use the New-Item cmdlet to create a new folder. The new folder will be created in the
c:\mytest directory. The name of the new folder will be comprised of the $strPrefix
constant “testFolder”, the number 0 from the $intPad variable, and the number contained
in the $i variable. The code that does this is seen here.
new-item -path c:\mytest -name $strPrefix$intPad$i -type directory}
12. The else script block is the same as the if script block, except that it does not include the
0 in the name that comes from the $intPad variable. Copy the new-item line of code from
the if statement, and delete the $intPad variable from the name argument. The revised
line of code is shown here.
{new-item -path c:\mytest -name $strPrefix$i -type directory}
14. Close the script block for the do clause and add the until statement. The condition that
until will evaluate is if the $i variable is equal to the value contained in the $intFolders
variable +1. The reason for adding 1 to $intFolders is so that the script will actually
create the same number of folders as is contained in the $intFolders variable. Because
this script uses a do …until loop and the value of $i is incremented prior to entering the
until evaluation, then the value of $i is always 1 more than the number of folders that are
created. This code is shown here.
}until ($i -eq $intFolders+1)
2. In the if … else statement, the New-Item cmdlet is used twice to create folders in the
c:\mytest directory. We want to delete these folders. To do this, we need to change the
New-Item cmdlet to the Remove-Item cmdlet. The two edited script blocks are shown
here.
{$intPad=0; remove-item -path c:\mytest -name $strPrefix$intPad$i} else {remove-item
-path c:\mytest -name $strPrefix$i}
Microsoft Confidential
Page 217 of 361
3. The Remove-Item cmdlet does not have a name argument. So we need to remove this
argument but retain the code that creates the folder name. We can replace -name with a
backslash:
{$intPad=0; remove-item -path c:\mytest\$strPrefix$intPad$i} else {remove-item -path
c:\mytest\$strPrefix$i}
4. The Remove-Item cmdlet does not take a type argument. Because this argument is not
needed, it can also be removed from both Remove-Item statements. The revised script
blocks are shown here.
{$intPad=0; Remove-item -path c:\mytest\$strPrefix$intPad$i} else {Remove-item -path
c:\mytest\$strPrefix$i}
Microsoft Confidential
Page 218 of 361
Microsoft Confidential
Lesson 7 Demonstration : Active Directory
Administration (ADSI)
The following section provides information and exercises for Active Directory
Administration using ADSI.
Introduction
Active Directory (AD) is Microsoft’s implementation of an X.500 compliant directory
service, which enables centralized access, security, and administration of network resources
using the Lightweight Directory Access Protocol (LDAP) standard.
The AD administrative tasks are commonly performed using two main GUI applications:
Active Directory Users & Computers
Active Directory Sites & Services
These applications are adequate for small addition, modification, and deletion tasks. The
applications become unmanageable when performing bulk operations in large forest
environments containing thousands or millions of objects.
Objectives
After completing this lab, you will be able to:
Understand how objects are organized in AD
Create, modify, and delete AD objects using PowerShell and ADSI
Prerequisites
Windows 2008 Server and Windows 7 Client Virtual Machines
Microsoft Confidential
Page 220 of 361
Objectives
In this exercise, you will:
Learn how objects stored in AD are organized
Access objects using the ADSI type accelerator
Prerequisites
Windows PowerShell v2 must be installed on a Windows 7 client machine. A Domain
Controller running Windows 2008 must be available on the network.
Directory Partitions
The AD database file (ntds.dit) is logically divided into a number of partitions, also known as
naming contexts. Partitioning data allows it to be replicated independently to domain
controllers in a single domain or the entire forest. There are three default AD partitions.
Domain All DCs in a Stores users, computers, groups, and other objects
Domain specific to a single domain
Configuration All DCs in the Stores sites, services, and partition information for the
Forest entire forest
Schema All DCs in the Stores the class and attribute definitions and rules for all
Forest objects in the entire forest
Directory Hierarchy
Although the underlying AD storage mechanism is table based, the directory server organizes
the data into a logical hierarchy of parent and child objects.
Microsoft Confidential
Page 221 of 361
Each item in the directory is identified by a name and a two-letter prefix, known as Relative
Distinguished Name (RDN). For example, all user, group, and computer objects are prefixed
by ‘CN’.
“CN=FinanceUser01”
To build a tree structure, a unique path to each object is created by concatenating an object’s
RDN with its parent container, until the top of the specific directory partition is reached.
This path is known as a Distinguished Name (DN) and uniquely identifies an object. DN
paths are used to connect to objects in order to create and manipulate them.
“CN=FinanceUser01,OU=Finance Users,OU=Corporate Users,DC=contoso,DC=com”
ADSI Providers
ADSI includes a number of service providers that allow access to different types of
directories. The following table lists service provider details.
The LDAP provider fully supports AD, but cannot be used to access Windows NT or the
local Security Accounts Manager (SAM) database.
The WinNT provider can be used to access Windows NT4 domain controller directory
servers, the local SAM database on client and member server machines as well as AD
implementations, but will only support features available on Windows NT domains.
The NDS and NWCOMPAT providers allow access to the Novell NDS implementations.
For example, in order to use the LDAP provider to connect to active directory objects, prefix
the LDAP moniker (the provider name plus the two forward slashes and colon character) to
the DN of the particular object.
Note: Unlike PowerShell, all the four provider strings listed above are case sensitive.
Microsoft Confidential
Page 222 of 361
“LDAP://DC=contoso,DC=com”
The above string will only appear on the screen when you type it in the PowerShell
console or include in a script.
2. To access AD, enter the [ADSI] PowerShell-type accelerator, followed by the binding
string.
PS C:\> $domain = [ADSI]“LDAP://DC=contoso,DC=com”
PS C:\> $domain
distinguishedName : {DC=contoso,DC=com}
Path :
3. If the computer is a domain member, you need not provide an LDAP moniker and DN,
replace it with an empty string.
By default, when the computer is a domain member, the binding string will be the root
current domain partition.
PS C:\> $domain = [ADSI]””
PS C:\> $domain
distinguishedName : {DC=contoso,DC=com}
Path :
distinguishedName : {DC=contoso,DC=com}
Path :
2. It is not a good practice to embed passwords in scripts, you may want to use the Get-
Credential Cmdlet to securely store the credentials in memory, and then pass them to
the ADSI provider. The LDAP provider only accepts plaintext passwords. A workaround
Microsoft Confidential
Page 223 of 361
distinguishedName : {DC=contoso,DC=com}
Path :
2. To bind to the nearest Global Catalog (GC) server in the forest, use the GC:// moniker.
[ADSI]”GC://DC=contoso,DC=com”
Microsoft Confidential
Page 224 of 361
Objectives
In this exercise, you will:
Search AD for different types of objects
Search for specific objects
Modify search options
Prerequisites
Windows PowerShell v2 must be installed on a Windows 7 client machine. A Domain
Controller running Windows 2008 must be available on the network.
2. Next, use the FindAll() method to execute the search. This operation will return all
objects in the domain partition.
$dirSearch.FindAll()
Path Properties
---- ----------
LDAP://DC=contoso,DC=com {minpwdlength, dc, msds-...
LDAP://CN=Users,DC=contoso,DC=com {iscriticalsystemobject,
systemFla...
LDAP://CN=Computers,DC=contoso,DC=com {iscriticalsystemobject,
systemFla…
LDAP://OU=Domain Controllers,DC=contoso,DC=com {iscriticalsystemobject,
systemfla…
Microsoft Confidential
Page 225 of 361
LDAP://CN=System,DC=contoso,DC=com {iscriticalsystemobject,
systemfla...
LDAP://CN=LostAndFound,DC=contoso,DC=com {iscriticalsystemobject,
systemfla...
LDAP://CN=Infrastructure,DC=contoso,DC=com {iscriticalsystemobject,
systemfla...
LDAP://CN=ForeignSecurityPrincipals,DC=contoso,DC=com {iscriticalsystemobject,
systemfla...
LDAP://CN=Program Data,DC=contoso,DC=com {objectclass, usncreated,
name...}
LDAP://CN=Microsoft,CN=Program Data,DC=contoso,DC=com {objectclass, usncreated,
name,...}
LDAP://CN=NTDS Quotas,DC=contoso,DC=com {iscriticalsystemobject,
systemfla...
LDAP://CN=Managed Service Accounts,DC=contoso,DC=com {objectclass, usncreated,
name...}
LDAP://CN=WinsockServices,CN=System,DC=contoso,DC=com {objectclass, usncreated,
name...}
LDAP://CN=RpcServices,CN=System,DC=contoso,DC=com {objectclass, usncreated,
name...}
LDAP://CN=FileLinks,CN=System,DC=contoso,DC=com {objectclass, usncreated,
name...}
...
= equal to (givenName=Chris)
| logical OR (|(givenName=Chris)(l=Sydney))
* Wildcard (givenName=Ch*)
Microsoft Confidential
Page 226 of 361
Note: The ‘=’ operator expressions are grouped by parentheses. The ‘&’ and ‘|’
operators are placed in front of the expressions wrapped in parentheses.
The default search filter is (objectClass=*). Since the wildcard operator is used, this search
filter will return all objects under the SearchRoot and all objects are derived from one or
more classes.
1. Typing the $dirSearch variable name displays the DirectorySsearcher object properties.
In this module, you will focus on the properties highlighted in bold.
$dirSearch
CacheResults : True
ClientTimeout : -00:00:01
PropertyNamesOnly : False
Filter : (objectClass=*)
PageSize : 0
PropertiesToLoad : {}
ReferralChasing : External
SearchScope : Subtree
ServerPageTimeLimit : -00:00:01
ServerTimeLimit : -00:00:01
SizeLimit : 0
SearchRoot : System.DirectoryServices.DirectoryEntry
Sort : System.DirectoryServices.SortOption
Asynchronous : False
Tombstone : False
AttributeScopeQuery :
DerefAlias : Never
SecurityMasks : None
ExtendedDN : None
3. Again, start the search by calling the DirectorySearcher object’s FindAll() method. You
will see a list of all user objects, in all child containers in the domain.
$dirSearch.findAll()
4. A more complex query could include a number of expressions combined with a logical
operator and wildcard character.
The following example uses the logical AND operator (&) to return all computer objects
whose operatingSystem attribute starts with the string “Windows Server”.
$dirSearch.filter = “(&(objectCategory=computer)(operatingSystem=Windows Server*))”
$dirSearch.findAll()
Path Properties
Microsoft Confidential
Page 227 of 361
---- ----------
LDAP://CN=CODC1,OU=Domain Controller... {primarygroupid, iscriticalsystemobj...
LDAP://CN=SQL2008R2,OU=SQL Servers,O... {primarygroupid, iscriticalsystemobj...
LDAP://CN=VMMS1,OU=SCVMM Servers,OU=... {primarygroupid, iscriticalsystemobj...
LDAP://CN=WEBSERVER,OU=Web Servers,O... {primarygroupid, iscriticalsystemobj...
LDAP://CN=EXCHANGE2010,OU=Exchange S... {primarygroupid, iscriticalsystemobj...
LDAP://CN=CODC2,OU=Domain Controller... {primarygroupid, iscriticalsystemobj...
LDAP://CN=CB-LP-SVR,OU=Clients,DC=co... {primarygroupid, iscriticalsystemobj...
LDAP://CN=COCA1,OU=Certificate Autho... {primarygroupid, iscriticalsystemobj...
LDAP://CN=COCM1,OU=Servers,DC=contos... {primarygroupid, iscriticalsystemobj...
LDAP://CN=CORODC1,OU=Domain Controll... {primarygroupid, iscriticalsystemobj...
Path Properties
---- ----------
LDAP://OU=AdminUsers,DC=contoso,DC=com {objectclass, usncreated, name...
LDAP://CN=Builtin,DC=contoso,DC=com {uascompat, objectguid, nextrid...
LDAP://OU=Clients,DC=contoso,DC=com {objectclass, usncreated,...
LDAP://CN=Computers,DC=contoso,DC=com {iscriticalsystemobject,
systemflags...
LDAP://OU=Domain Controllers,DC=contoso,DC=com {iscriticalsystemobject,
systemflags...
LDAP://OU=Exchange Servers,DC=contoso,DC=com {objectclass, usncreated...
LDAP://CN=ForeignSecurityPrincipals,DC=cont... {iscriticalsystemobject,
systemflags...
LDAP://OU=Groups,DC=contoso,DC=com {objectclass, usncreated, name...
LDAP://CN=Infrastructure,DC=contoso,DC=com {iscriticalsystemobject,
systemflags...
LDAP://CN=LostAndFound,DC=contoso,DC=com {iscriticalsystemobject,
systemflags...
LDAP://CN=Managed Service Accounts,DC=conto... {objectclass, usncreated, name...
...
Task 4: MaxPageSize
In a large AD environment with hundreds of thousands or even millions of objects in the
forest, a DirectorySearch operation could return a huge number of results.
AD imposes a limit on the maximum number of results returned from a search. This
limitation allows you to conserve DC resources. The MaxPageSize setting at the top of the
domain partition controls this limit and is set to a default of 1,000 objects for each query.
Microsoft Confidential
Page 228 of 361
Name Description
AttributeScopeQuery Gets or sets the LDAP display name of the DN attribute to search.
Only one attribute can be used for this type of search.
CacheResults Gets or sets a value indicating if the result is cached on the client
computer.
ClientTimeout Gets or sets the maximum amount of time that the client waits for the
server to return results. If the server does not respond within this time,
the search is aborted and no results are returned.
DerefAlias Gets or sets a value indicating how the aliases of objects that are
found during a search should be resolved.
ExtendedDN Gets or sets a value that indicates the format of the DNs.
Filter Gets or sets a value indicating the LDAP format filter string.
PageSize Gets or sets a value indicating the page size in a paged search.
PropertiesToLoad Gets a value indicating the list of properties to retrieve during the
search.
PropertyNamesOnly Gets or sets a value indicating if the search retrieves only the names
of attributes to which values have been assigned.
Microsoft Confidential
Page 229 of 361
SearchRoot Gets or sets a value indicating the node in the AD Domain Services
hierarchy where the search starts.
SearchScope Gets or sets a value indicating the scope of search that is observed by
the server.
SecurityMasks Gets or sets a value indicating which security access information for
the specified attributes should be returned by the search.
ServerPageTimeLimit Gets or sets a value indicating the maximum amount of time the
server should search for an individual page of results. This is not the
same as the time limit for the entire search.
SizeLimit Gets or sets a value indicating the maximum number of objects that
the server returns in a search.
Sort Gets or sets a value indicating the property on which the results are
sorted.
Tombstone Gets or sets a value indicating if the search should also return deleted
objects that match the search filter.
VirtualListView Gets or sets a value indicating the virtual list view options for the
search.
Microsoft Confidential
Page 230 of 361
Objectives
In this exercise, you will:
Understand how to create new user, computer, and group objects in AD
Learn how to modify object attributes
Add users to groups
Manipulate the UserAccountControl attribute
Create and modify multiple objects in the directory
Prerequisites
Windows PowerShell v2 must be installed on a Windows 7 client machine. A Domain
Controller running Windows 2008 must be available on the network.
Computer CN=
Group CN=
Microsoft Confidential
Page 231 of 361
Figure 4:
Note: The Create() method is hidden when viewing the object members using the Get-
Member Cmdlet.
1. To use this method to create a new Organizational Unit object at the root of the domain,
first bind to the Domain Root DN, and save a reference to it in a variable.
$objRoot = [ADSI]”LDAP://DC=contoso,DC=com”
3. The new OU object is now created on the local machine. You must now save the object
to the directory. To save the object, use the SetInfo() method on the $objOU variable.
Microsoft Confidential
Page 232 of 361
$objOU.SetInfo()
distinguishedName : {OU=Finance,DC=contoso,DC=com}
Path : LDAP://ou=Finance,dc=contoso,dc=com
2. Use the OU’s Create() method to create the new user object.
Note: You must change the class to ‘user’ and the RDN prefix to ’CN=’.
$objUser = $objOU.Create(“user”,“CN=FinanceUser01”)
3. At this point, it is a good practice to set the samAccountName property of the new
object. Otherwise, the system will automatically create a random unique value similar to
$A91000-B3973K23LNTD. Such values are not very user-friendly log on names.
To set object attributes, use the Put() method on the new user object. Pass the name of
the attribute you want to set along with its new value.
In this example, set the user object’s samAccountName attribute value to
“FinanceUser01”.
$objUser.Put(“samaccountname”,”FinanceUser01”)
Microsoft Confidential
Page 233 of 361
Figure 5:
These settings are stored as binary mask in a property called UserAccountControl on a user
object. Each bit position represents a different possible user account option that can be
checked or unchecked.
Multiple settings can be combined using PowerShell’s binary logical operators and are shown
in the following table.
Microsoft Confidential
Page 234 of 361
Value in Value in
Property Flag
Hexadecimal Decimal
SCRIPT 0x0001 1
ACCOUNTDISABLE 0x0002 2
HOMEDIR_REQUIRED 0x0008 8
LOCKOUT 0x0010 16
PASSWD_NOTREQD 0x0020 32
PASSWD_CANT_CHANGE 0x0040 64
For example, to disable a user account you must perform a binary exclusive OR logical
operation (XOR) on the current value of the UserAccountControl property.
5. First, save the current value of the UserAccountControl property into a variable.
$uac = $objUser.userAccountControl.value
Microsoft Confidential
Page 235 of 361
6. In the above table, find the bit position that controls the option you need to set. In this
case, it is 0x0002. For clarity I have saved the number into a more descriptive variable
name first.
Note: It is possible to use either the hexadecimal or decimal values.
$ACCOUNTDISABLE = 0x0002
7. Next, perform the XOR operation on the $uac variable using PowerShell’s –bxor
operator. This enables (sets to 1) the second bit position in the UserAccountControl
bitmask.
$objUser.UserAccountControl = $uac –bxor $ACCOUNTDISABLE
It is a good practice to test if the bit position is already set before changing it, as the XOR
operator blindly flips the bit on to off and vice versa.
To do this, use the binary AND logical operator to check if the option is set.
If the result is 0, the bit position is turned off ($false).
Any positive integer indicates the bit is turned on ($true).
9. Save the value, representing the Password never expires option into a variable.
$DONT_EXPIRE_PASSWORD = 0x10000
12. Use an IF statement and a –band operator to determine whether the bit is already turned
on. If it is not, turn the bit position on (flip the bit) using the –bxor operator.
if ($uac –band $DONT_EXPIRE_PASSWORD)
{
“Password never expires is already set”
}
else
{
“Password never expires is NOT set”
“Setting the password to never expire…”
$objUser.UserAccountControl = $uac –bxor $DONT_EXPIRE_PASSWORD
$objUser.SetInfo()
}
13. To set multiple options at once, add them together and use the binary OR operator as
follows.
$SMARTCARD_REQUIRED = 0x40000
Microsoft Confidential
Page 236 of 361
Microsoft Confidential
Page 237 of 361
4. Set the GroupType property of the new group object to one of its possible values, shown
in the following table.
Group Type Hexadecimal Value Decimal Value
Built-in Local 0x00000001 1
Global 0x00000002 2
Universal 0x00000008 8
$BUILTIN_LOCAL_GROUP = 0x00000001
$GLOBAL_GROUP = 0x00000002
$DOMAIN_LOCAL_GROUP = 0x00000004
$UNIVERSAL_GROUP = 0x00000008
$SECURITY_ENABLED_GROUP = 0x80000000
Note: If you set only the GroupType to one of the first four values, a distribution group,
rather than a security group will be created.
6. Calculate the Global group binary value, and save it in the $intGlobalGroup variable.
$intGlobalGroup = $GLOBAL_GROUP –bor $SECURITY_ENABLED_GROUP
7. Set the groupType attribute to the $intGlobalGroup variable using the Put() method.
$objGroup.Put(“grouptype”, $intGlobalGroup)
Microsoft Confidential
Page 238 of 361
3. Use the group’s Add() method, specifying the user’s path property as the argument.
$objGroup.Add($objUser.Path)
2. Use the Create() method of the OU object to create the new computer object, and save
the resulting object in the $objComputer variable.
Note: Change the RDN name to ‘NewPC001’ and the object class to ‘computer’.
$objComputer = $objOU.Create(“computer”,“CN=NewPC001”)
4. Computer objects are also disabled by default. To enable them, set the AccountDisabled
property to false.
$objComputer.AccountDisabled = $false
Microsoft Confidential
Page 239 of 361
Objectives
This lab explores how to create, modify, and search AD objects using Windows Powershell
and ADSI.
Prerequisites
The lab requires a domain joined Windows 7 client and a Windows 2008 Domain Controller.
Microsoft Confidential
Page 240 of 361
Scenario
Most AD environments require the creation of many objects in a batch operation. You can
use many of the examples covered previously in this lesson to build a user creation script.
Objectives
The script will perform the following operations:
Take input from a .csv file to provide individual user details
Create three Organizational Units (OU), global groups, and department manager accounts
Create each batch of users listed in the userlist.csv file
Set a number of single and multivalued attributes
Add each user to a particular global group
Enable the user account and require password to be changed at first log on
4. Add a foreach loop to iterate through the users imported from the userlist.csv file.
foreach ($user in $users)
{
5. Create OUs to hold each batch of users. Check whether the OU exists before creating it
using the [ADSI] type accelerator’s Exists() static method.
if (-not [adsi]::Exists("LDAP://OU=$($user.Department), DC=contoso,DC=com"))
{
$objOU = $objDomainRoot.Create("organizationalunit","OU=$($user.Department)")
$objOU.SetInfo()
}
Microsoft Confidential
Page 241 of 361
6. Create the department global groups. Check whether the group exists before creating it
using the [ADSI] type accelerator’s Exists() static method.
if (-not
[ADSI]::Exists("LDAP://CN=$($user.Group),OU=$($user.Department),DC=contoso,DC=com"
))
{
$objOU = [ADSI]"LDAP://OU=$($user.Department),DC=contoso,DC=com"
$objGroup = $objOU.Create("group","CN=$($user.Group)")
$objGroup.SetInfo()
}
7. Create department manager user accounts. Check whether they exists before creating
them using the [ADSI] type accelerator’s Exists() static method.
if (-not
[ADSI]::Exists("LDAP://CN=$($user.Manager),OU=$($user.Department),DC=contoso,DC=co
m"))
{
$objOU = [ADSI]"LDAP://OU=$($user.Department),DC=contoso,DC=com"
$objUserManager = $objOU.Create("user","CN=$($user.Manager)")
$objUserManager.SetInfo()
9. Take the first letter of current user’s firstname property and concatenate it with the
surname property.
$samaccountname = $user.firstName.substring(0,1) + $user.Surname
10. Set the account’s single valued attributes using the Put() method.
$objUser.Put("givenName",$user.firstName)
$objUser.Put("sn",$user.Surname)
$objUser.Put("samaccountname",$samaccountname)
$objUser.Put("displayName",$samaccountname)
$objUser.Put("UserPrincipalName","[email protected]")
$objUser.Put("company","Contoso")
$objUser.Put("department",$user.Department)
$objUser.Put("homePhone","029870112233")
$objUser.Put("postOfficeBox","100")
$objUser.Put("streetAddress","1 Epping Road")
$objUser.Put("l","Sydney")
$objUser.Put("st","NSW")
$objUser.Put("postalCode","2122")
$objUser.Put("c","AU")
$objUser.Put("co","Australia")
Microsoft Confidential
Page 242 of 361
$objUser.Put("countryCode","36")
$objUser.SetInfo()
11. Set the otherHomePhone multivalued attribute using the PutEx() method.
$arrPhone = "029870123456","029870123457","029870123458"
$objUser.PutEx(2,"otherHomePhone",$arrPhone)
$objUser.SetInfo()
12. Set the user’s manager attribute to the DN of the manager account.
$objUserManager =
[ADSI]"LDAP://CN=$($user.Manager),OU=$($user.Department),DC=contoso,DC=com"
$objUser.Manager += $objUserManager.distinguishedname
15. Run the script, and confirm that it worked correctly by checking ADUC, verify that the
users had been created in the LabUser OU.
Microsoft Confidential
Page 243 of 361
Microsoft Confidential
Page 244 of 361
Objectives
After completing this lab, you will be able to:
Understand Active Directory administration with Windows Powershell, using the Active
Directory module and cmdlets
Pre-requisites
Windows 2008 Server and Windows 7 workstation logged onto with Domain Administrator
credentials
Microsoft Confidential
Page 245 of 361
Scenario
The Active Directory module for Windows PowerShell is a Windows PowerShell module,
named ActiveDirectory, that consolidates a group of cmdlets. These cmdlets can be used to
manage the Active Directory domains in a single, self-contained package.
Prerequisites
Windows PowerShell and the .NET Framework 3.5.1 must be installed on a Windows Server
2008 R2 or Windows 7 computer to use the Active Directory module.
You can install the Active Directory module by using any of the following methods:
By default, on a Windows Server 2008 R2 server when you install the ADDS
By default, when you make a Windows Server 2008 R2 server a Domain Controller
As part of the Remote Server Administration Tools (RSAT) feature on a Windows Server
2008 R2 server
As part of the RSAT feature on a Windows 7 computer
If you want to use the Active Directory module to manage an Active Directory domain, the
Active Directory Web Services (ADWS) service must be installed on at least one Domain
Controller in this domain.
ADWS is installed and runs by default on a Windows Server 2008 R2 Domain Controller.
For Domain Controllers running on Windows Server 2008, Windows Server 2003 R2
SP2 and Windows Server 2003 SP2 install the Active Directory Management Gateway
Service that provides a Web service interface to Active Directory domains
The Active Directory module is available in the following editions of Windows Server 2008
R2 and Windows 7:
Windows Server 2008 R2 Standard
Windows Server 2008 R2 Enterprise
Windows Server 2008 R2 Datacenter
Windows 7
Now you will load the Active Directory module for Windows PowerShell in different ways.
Microsoft Confidential
Page 246 of 361
The output lists of all the modules can be imported into the session.
7. Now type the following command.
Import-Module Activedirectory
8. You can list all cmdlets available from this module, as follows:
Get-Command -Module "ActiveDirectory"
Microsoft Confidential
Page 247 of 361
Task Description
1. You can use the Active Directory module provider to map Active Directory domains to
specific provider drives. When the Active Directory module is first loaded, a default
Active Directory drive (AD:) is mounted with the root path set to RootDSE of the local
forest.
To connect to the AD: drive, run the following command:
PS c:\>cd AD:\
The Active Directory provider can be used to easily connect to any of the partitions to
query or make changes.
3. To connect to a domain, type the following command:
PS AD:\> Cd “dc=contoso,dc=com”
PS AD:\DC=contoso,DC=com>
4. Using dir, you can enumerate the objects in the domain, as follows:
PS AD:\DC=contoso,DC=com> dir
5. You can also connect to a child OU or container using its Distinguished Name (DN) or
Relative Distinguished Name (RDN).
The following command will set the location to the drive
AD:\OU=Test,DC=contoso,DC=com
Microsoft Confidential
Page 248 of 361
PS AD:\DC=contoso,DC=com>cd “OU=test”
6. The Active Directory PSProvider can be used to create a PSDrive, which connects to the
Active Directory with specific or logged on credentials.
The following command creates a new provider drive to an Active Directory domain
using the New-PSDrive cmdlet:
New-PSDrive -PSProvider ActiveDirectory -Name Contoso `
-Root "AD:\dc=contoso,dc=com"
The other optional parameters commonly used with the cmdlet New-PSDrive are Server
and Credential.
7. In order to use the domain, server, credentials or set the search base to a specific path of
the drive, set the location (cd) to the created PSDrive.
PS c:\>set-location Contoso:\
PS Contoso:\>
Certain generic cmdlets shown in the following table can be used with the Active Directory
provider.
Get-PSProvider New-PSDrive Get-PSDrive
Objects can be searched, added, deleted or modified using Active Directory cmdlets, which
will be covered in the later sections of the module.
Microsoft Confidential
Page 249 of 361
The Active Directory cmdlets can be used to retrieve information, add, create, delete, move,
rename, reset, restore, search objects, set properties, enable or disable objects and features
and unlock accounts.
A group of tasks can be completed using the cmdlets to manage the following:
Account Management
Group Management
Managed Service Accounts
Organizational Units
Password Policies
Optional Features
Search\Modify Objects
Forest and Domain Management
Domain Controller
Operations Master Management
Microsoft Confidential
Page 250 of 361
4. Create a new user named 'Tkim' and set the EmployeeID and mail attributes.
New-ADUser tkim –OtherAttributes @{employeeid="12345";mail="[email protected]"}
Microsoft Confidential
Page 251 of 361
GUID (objectGUID)
Security Identifier (objectSid)
SAM User Name (sAMUserName)
ADUser Distinguished Name
GUID (objectGUID)
Security Identifier (objectSid)
SAM User Name (sAMUserName)
ADObject Distinguished Name
GUID (objectGUID)
ADOrganizationalUnit Distinguished Name
GUID (objectGUID)
1. The following examples show how the identity parameter is used to retrieve a specific
user by using different attributes:
#match on SamAccountName
PS Contoso:\> Get-ADUser -Identity "tkim"
#SID
PS Contoso:\> Get-ADUser -Identity "S-1-5-21-1989273325-1845373034-100956730-1604"
#DistinguishedName
PS Contoso:\> Get-ADUser "CN=tkim,OU=test1,DC=contoso,DC=com"
#ObjectGUID
PS Contoso:\> Get-ADUser "fc1afcab-5c3a-400a-9d91-16431452111b"
Note: The SID and GUID used in the examples above may not match your lab
environment.
Microsoft Confidential
Page 252 of 361
Task Description
1. Type the following commands to list the cmdlets used to search AD object(s) of various
classes.
PS Contoso:\> gcm get-ad* | ft name
Name
----
Get-ADAccountAuthorizationGroup
Get-ADAccountResultantPasswordReplicationPolicy
Get-ADComputer
Get-ADComputerServiceAccount
Get-ADDefaultDomainPasswordPolicy
Get-ADDomain
Get-ADDomainController
Get-ADDomainControllerPasswordReplicationPolicy
Get-ADDomainControllerPasswordReplicationPolicyUsage
Get-ADFineGrainedPasswordPolicy
Get-ADFineGrainedPasswordPolicySubject
Get-ADForest
Get-ADGroup
Get-ADGroupMember
Get-ADObject
Get-ADOptionalFeature
Get-ADOrganizationalUnit
Get-ADPrincipalGroupMembership
Get-ADRootDSE
Get-ADServiceAccount
Get-ADUser
Get-ADUserResultantPasswordPolicy
2. In the previous exercise, you have discussed about retrieving object information using the
Identity parameter.
For example:
Get-ADUser -Identity tkim
In order to search the Active Directory based on a pattern or criteria, using an appropriate
filter syntax becomes important. You can use the Filter or LDAPFilter parameter to
specify a query string that retrieves Active Directory objects.
In addition, certain parameters such as ResultPageSize, SearchBase or SearchScope can
be used to search the Active Directory efficiently.
3. The following command gets all the Security groups that have a Group Scope of
DomainLocal in the OU named Test1.
get-adgroup -Filter 'GroupCategory -eq "Security" -and GroupScope -eq
"DomainLocal"' –SearchBase ‘OU=Test1,dc=contoso,dc=com’
Microsoft Confidential
Page 253 of 361
Microsoft Confidential
Page 254 of 361
Task Description
1. In your PowerShell console, type the following commands to get the cmdlets used to
create new AD objects of various classes.
PS Contoso:\> gcm new-ad* -commandtype cmdlet | ft name
Name
----
New-ADComputer
New-ADFineGrainedPasswordPolicy
New-ADGroup
New-ADObject
New-ADOrganizationalUnit
New-ADServiceAccount
New-ADUser
2. To create new users, you can use the New-ADUser cmdlet, as shown in the following
example:
PS Contoso:\> $pass = ConvertTo-SecureString "P@ssword1" -AsPlainText –Force
The ConvertTo-SecureString cmdlet shown above creates a secure string which is needed
to specify the User Account password.
3. Consider another scenario where you will create a list of users from a CSV file.
The column headers in the CSV file may or may not match the Active Directory attribute
names used by New-ADUser cmdlet.
For instance, if the column headers are “GivenName”, “Surname,” “Title,” “Department,”
“EmployeeId”, “Mail” and so on, or assuming that after receiving the CSV file you
modified the column headers to match the attribute names, the following command will
create bulk users.
PS Contoso:\>Import-CSV c:\pshell\part1\lesson8\userlist.csv | New-ADUser
4. If the column headers do not match the attribute names, the cmdlet Select-Object can be
used to calculate the properties as shown in the following example.
PS Contoso:\>Import-CSV c:\pshell\part1\lesson8\userlist.csv | Select `
@{Name="GivenName";Expression={$_."First Name"}}, `
@{Name="Surname";Expression={$_."Last Name"}}, `
Microsoft Confidential
Page 255 of 361
@{Name="Title";Expression={$_."Job Title"}}, `
@{Name="Department";Expression={$_.Section}}, `
@{Name="Employeeid";Expression={$_."Employee ID"}} | New-ADUser
5. Now explore the cmdlet New-ADGroup to create a new group named 'Managers' in the
container 'CN=Users,DC=Contoso,DC=Com' and set the GroupCategory, DisplayName,
GroupScope, and Description properties on the new object.
C:\PS>New-ADGroup -Name "Managers" -SamAccountName Managers -GroupCategory
Security -GroupScope Global -DisplayName "Managers" -Path
"CN=Users,DC=Contoso,DC=Com" -Description "Members of this group are floor
Managers”
Microsoft Confidential
Page 256 of 361
Task Description
1. In your PowerShell console, type the following command to get the cmdlets used to
modify AD objects of various classes.
PS Contoso:\> gcm set-ad* -commandtype cmdlet | ft name
Name
----
Set-ADAccountControl
Set-ADAccountExpiration
Set-ADAccountPassword
Set-ADComputer
Set-ADDefaultDomainPasswordPolicy
Set-ADDomain
Set-ADDomainMode
Set-ADFineGrainedPasswordPolicy
Set-ADForest
Set-ADForestMode
Set-ADGroup
Set-ADObject
Set-ADOrganizationalUnit
Set-ADServiceAccount
Set-ADUser
2. A simple example shown below updates the company and department attributes on a
single target identity.
Set-ADUser Dpark -Company ‘Contoso’ -Department 'Sales'
Bulk Modifications
You might encounter scenarios with many users in an environment, who do not have a
UserPrincialName (UPN) configured. In these scenarios, you can use Get-ADUser to search
for users without a UPN and pipe the results to Set-ADUser to modify the user accounts.
3. If you simply want to set the user account to be the sAMAccountName with the domain
suffix, you can use a command similar to the one shown below:
Get-ADUser -filter {UserPrincipalname -notlike "*"} | ForEach-Object {Set-ADuser -
Identity $_ -UserPrincipalName "$($_.sAMAccountName)@contoso.com"}
Microsoft Confidential
Page 257 of 361
Task Description
1. If you specify a user name for this parameter, the cmdlet prompts for a password.
Get-ADComputer –filter ‘samaccountname –notlike “syd*”’ –searchbase ‘OU=Domain
Controllers,DC=contoso,dc=com’ -credential contoso\administrator
2. You can also create a PSCredential object by using a script or by using the Get-
Credential cmdlet. You can then set the Credential parameter to the PSCredential object.
3. The following example shows how to create credentials.
$DomainCreds = Get-Credential "Contoso\administrator"
4. The following shows how to set the Credential parameter to these credentials.
Get-ADuser –Identity tkim -Credential $DomainCreds
5. Often, when using alternate credentials or specifying specific server connection settings,
it can become tedious to specify these parameters for every cmdlet being used. In
addition, each time you specify these parameters, a new session is set up, which has some
performance costs associated with it. A better approach is to use the Active Directory
PSProvider to create a PSDrive, which connects to the Active Directory.
New-PSDrive -PSProvider ActiveDirectory -Name Contoso -Root `
"AD:\dc=contoso,dc=com" –credential $DomainCreds
The syntax shown above creates a PSdrive named Contoso connected with the credentials
specified in the DomainCreds variable.
Microsoft Confidential
Page 258 of 361
Prerequisites
The lab requires a windows 7 client running in a domain environment.
Microsoft Confidential
Page 259 of 361
Scenario
The AD administrator of Contoso Limited receives a request for creating lab users for their
development work. The users belong to the same physical location, hence a common address.
In addition to the name, surname, UPN and e-mail address attributes, the users would also
have a home directory and roaming profile stored on the respective shares on the server
Syddc01.
The administrator will have to automate the user creation using the Active Directory modules
for Windows PowerShell.
Duration
10 minutes
This will ensure that only errors related to the script are reported.
6. Type the following line to load the Active Directory module.
Import-module activedirectory
Microsoft Confidential
Page 260 of 361
7. In order to create an OU named “LabUsers” in which the users will be created, type the
following line
New-ADOrganizationalUnit -Name LabUsers -Path "DC=CONTOSO,DC=COM”
8. Type the following code for the next line of the script
$aryText = Get-Content -Path "c:\pshell\part1\lesson8\labs\address.txt"
This will load the address details from the file that will be used for the user accounts.
9. On the next line, type the following code to create a variable for the username prefix.
$Username = "LabUser"
10. On the next line, type the following code to create the variable for the max user count.
$intUsers = 9
11. On the next line, type the following code to create a variable for the user path.
$userpath = "OU=LabUsers,DC=contoso,DC=com"
12. On the next line, type the following code on the next line to start the for loop.
for ($i=1; $i -le $intUsers; $i++)
13. On the next line, type the following code to open the script block.
{
14. On the next line, type the following code to create each user account with the attributes to
be populated in the General, Address and Profile tabs.
new-aduser -name $username$i -samaccountname $username$i -path $userpath `
-displayname "$username$i" -givenname "$username$i" -surname "surname" `
-Initials $i -Description $($aryText[0]) `
-UserPrincipalName "[email protected]" `
-EmailAddress "[email protected]" -StreetAddress "$($aryText[1])" `
-city "$($aryText[2])" -state "$($aryText[3])" -PostalCode "$($aryText[4])" `
-OfficePhone "02-$i$i$i$i-$i$i$i$i" `
-ProfilePath "\\syddc01\users\$username$i" -HomeDrive "h" `
-HomeDirectory "\\syddc01\userdata\$username$i"
15. On the next line, type the following code to close out the For loop.
}
The script should execute and create the users and populate the user properties.
19. In ADUC, check for the users in the LabUsers OU.
Microsoft Confidential
Page 261 of 361
20. Check one of the users property tabs. You will see that the user properties have been
populated.
Microsoft Confidential
Page 262 of 361
Scenario
The Contoso management requires redeployment of first five lab users to a different
development project. From now on, those lab users will be located at a different office.
The AD administrator requires to automate the change of address details using the Active
Directory modules for Windows PowerShell.
Duration
10 minutes
This will ensure that only errors related to the script are reported.
6. Type the following line to load the Active Directory module.
Import-module activedirectory
7. Type the following code for the next line of the script.
$aryText = Get-Content -Path "c:\pshell\part1\lesson8\labs\NewAddress.txt"
This will load the address details from the file that will be used to change or update the
address details of the user accounts.
8. On the next line, type the following code to create a variable for the username prefix.
$Username = "LabUser"
Microsoft Confidential
Page 263 of 361
9. On the next line, type the following code to create the variable for the max user count to
be modified.
$intUsers = 5
10. On the next line, type the following code on the next line to start the For loop.
for ($i=1; $i -le $intUsers; $i++)
11. On the next line, type the following code to open the script block.
{
12. On the next line, type the following code to modify the target user accounts’ address
details.
set-aduser -identity $username$i -StreetAddress "$($aryText[0])" `
-city "$($aryText[1])" -state "$($aryText[2])" -PostalCode "$($aryText[3])"
13. On the next line, type the following code to close out the For loop.
}
The script should execute and modify the users’ address details.
In ADUC, refresh the view and check for the users in the OU.
17. Check one of the users Address property tab. You will see that the user properties have
been modified.
18. Open the script c:\pshell\part1\lesson8\lab8\lab8-ex2.ps1 and save it as
c:\pshell\part1\lesson8\lab8\lab8-ex2a.ps1
19. Now delete the following lines of code from the script.
set-aduser -identity $username$i -StreetAddress "$($aryText[0])" `
-city "$($aryText[1])" -state "$($aryText[2])" -PostalCode "$($aryText[3])"
20. Now type the following code between the { and } lines
Remove-aduser -Identity "$username$i"
Microsoft Confidential
Page 264 of 361
Scenario
During an Active Directory disaster recovery exercise, Contoso DR management team
expressed the requirement to have a script that would populate all the objects that have been
deleted in the last seven days.
The AD administrator will need to write the script that will search the Deleted Objects
container and list the objects deleted in the last seven days.
Duration
10 minutes
This will ensure that only errors related to the script are reported.
5. Type the following line to load the Active Directory module.
Import-module activedirectory
6. Type the following code for the next line of the script to specify the CSV file path to
which the output will be exported.
$csvpath = "c:\pshell\part1\lesson8\labs\deletedobjects.csv"
7. On the next line, type the following code to create a variable to store the datetime
(current date – 7 days) object.
$deletedindays = (get-date).adddays("-7")
8. On the next line, type the following code to create the variable for the search filter string.
$searchfilter= 'isdeleted -eq $true -and whenchanged -gt $deletedindays'
Microsoft Confidential
Page 265 of 361
The filter above would search for objects that have their IsDeleted attribute set to True
and the whenchanged attribute is within the last 7 days.
9. On the next line, type the following code to search AD according to the filter string
(including the Deleted Objects container) and store the result in the designated CSV file.
Get-ADObject -Filter $searchfilter -IncludeDeletedObjects | select
name,objectclass | export-csv -Path $csvpath -notypeinformation
Microsoft Confidential
Page 266 of 361
Microsoft Confidential
Lesson 9 Demonstration : Windows Management
Instrumentation (WMI)
Introduction
In this section, you will cover the core concepts of Windows Management Instrumentation,
better known as ‘WMI’. These concepts include working with classes, gathering data both
locally and remotely as well as real-world applications.
Objectives
After completing this lab, you will be able to:
Describe the core WMI concepts in Windows
Leverage the Get-WMIObject cmdlet to access WMI from within PowerShell
Review some of the most commonly used WMI classes
Discover gathering data remotely using Get-WMIObject
Filter and sort returned WMI data
Provide best practices when leveraging WMI in scripting
Prerequisites
A Windows 7 workstation logged in with administrator credentials
A Windows 2008 server logged in with administrator credentials
Microsoft Confidential
Page 268 of 361
Scenario
WMI is an integral part of Windows infrastructure and is installed by default. In this scenario,
we will explore the WMI Management console and underlying services.
Concepts of Instrumentation
Instrumentation is the act of making data available through an avenue of communication. In
programming terms, that translates to being able to gather trace information, performance
data or verbose error logging.
Instrumentation can be fully understood in a more familiar context. Consider an automobile.
When we want to know the status of a vehicle's component, we rely on instrumentation to do
it. Since we cannot “speak” directly to the car, we have to use an infrastructure that allows
communication. The gauge on the dashboard interacts with various sensors throughout the
vehicle and translates data, allowing you to see various conditions (such as current speed and
fuel level).
Hardware (Engine) Data Translation (Gauge) Object
Instrumentation in Windows is very similar. It allows drivers and components to output data
that can then be used by users or other processes. This effectively allows us to “speak” to
deeper layers of the OS and hardware.
Microsoft Confidential
Page 269 of 361
WMI Organization
WMI is built around the concepts of Classes, Instances and Namespaces.
A Class is essentially anything WMI can manage. It is a template for an underlying object
and describes its function. All objects of each Class follow the same basic layout; however,
the actual data they contain is unique to that object.
Common Class Types
Hardware Classes Describe Hardware events/data (static)
Software Classes Describe Software events/data (dynamic)
Operating System Classes Describe OS specific information
Performance Counter Classes Describe Performance data (Perfmon) counters
An Instance represents the objects within each class. Each object follows a template
described by the parent Class in which it resides.
Namespaces are logical groupings of Classes.
Namespace
SERVICE_NAME: winmgmt
TYPE : 20 WIN32_SHARE_PROCESS
Microsoft Confidential
Page 270 of 361
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 0 IGNORE
BINARY_PATH_NAME : C:\Windows\system32\svchost.exe -k netsvcs
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : Windows Management Instrumentation
DEPENDENCIES : RPCSS
SERVICE_START_NAME : localSystem
SERVICE_NAME: winmgmt
TYPE : 20 WIN32_SHARE_PROCESS
STATE : 4 RUNNING
(STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
Name : winmgmt
RequiredServices : {RPCSS}
CanPauseAndContinue : True
CanShutdown : True
CanStop : True
DisplayName : Windows Management Instrumentation
DependentServices : {WinTarget, vmms, vhdsvc, SharedAccess...}
MachineName : .
ServiceName : winmgmt
ServicesDependedOn : {RPCSS}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
Site :
Container :
The PowerShell output varies slightly from the SC.EXE returned information.
You will now see a list of the available namespaces in the WMI repository from the root.
This, however, is only the top layer of the available namespaces. There are sub-
namespaces available but the command above does not display them.
2. In the PowerShell console, run the script recurse-namespaces.ps1
Microsoft Confidential
Page 271 of 361
This script will display all the namespaces and sub-namespaces available for the current
machine.
For almost all purposes, you will use the root\cimv2 namespace.
function searchns($ns)
{
write-host $ns -foregroundcolor white
$colns = get-wmiobject -namespace $ns -class "__namespace"
if ($colns -ne $null)
{
foreach ($i in $colns)
{
$subns = $i.__namespace+"\"+$i.name
searchns($subns)
}
}
}
Write-host "The Following are all the namespaces and sub namespaces in `n WMI on
the local machine" -foregroundcolor green
searchns("root")
This script will now display the full list of available WMI namespaces and sub-name
spaces. You will notice that there are many available namespaces and sub-namespaces.
Microsoft Confidential
Page 272 of 361
You will now see a list of the available WMI classes for the root\cimv2 namespace.
Root\cimv2 is the default namespace used by WMI. This default namespace is used by
the get-wmiobject Cmdlet if you do not specify it.
2. Type the following to display only the names of the WMI classes.
Get-wmiobject –list | select name
As you can see from the output, this displays all the properties of the class without the
metadata. You can use the range wildcard to out the metadata for all WMI classes and
other queries.
Microsoft Confidential
Page 273 of 361
1. From the examples, it appears that the get-wmiobject cmdlet can return a wide variety
of data from WMI objects. Now, perform a basic query on a Logical Disk Class.
Get-WmiObject –Class “Win32_LogicalDisk”
DeviceID : C:
DriveType : 3
ProviderName :
FreeSpace : 87575044096
Size : 497958252544
VolumeName : Windows 7
DeviceID : E:
DriveType : 5
ProviderName :
FreeSpace :
Size :
VolumeName :
You will notice that in this query, the namespace is not specified. PowerShell will use:
The default WMI scripting namespace defined via the WMI control console, or
What is defined in the registry key HKLM:\Software\Microsoft\WBEM\Scripting Default
namespace
From this simple query, you can gather some useful information related to the current disk-
related hardware on the machine. The first entry lists the DeviceID “C:” and a DriveType of 3.
There are other fields designating metrics such as Total Size and Volume Name.
The second entry had a DeviceID of “E:” and has a different DriveType of 5. Note that there
is no data for other fields.
DriveType Reference
# Type:
--------------------------------------------------------------------------------------------------------------
1 No Root Directory
2 Removable Disk
3 Local Disk
4 Network Drive
5 Compact Disc
6 RAM Disk
From this quick data collection, you can infer that “C” is a Hard Disk approximately
500Gigabytes in size, while “E” is a CD/DVD unit with no media loaded.
For further details, you can use the WMI SDK file reference that is on the desktop of the
workstation. The file is WMISKD_School.chm. You can find details for every WMI class in
the MSDN documentation website.
Microsoft Confidential
Page 274 of 361
Now, expanding on that concept, look at the Win32_Bios class and see what data can be
gathered about the machine:
PS> Get-WmiObject –Class Win32_Bios
SMBIOSBIOSVersion : 090004
Manufacturer : American Megatrends Inc.
Name : BIOS Date: 03/19/09 22:51:32 Ver: 09.00.04
SerialNumber : 0654-6116-5806-0058-2049-6801-11
Version : VRTUAL - 3000919
This returned only a small portion of the available data held in the Win32_Bios class. To get
the full output, pipe the contents to a Format-List.
Get-WmiObject –class Win32_Bios | fl *
You will see here that the WMI metadata is also returned. To filter this metadata out, you can
use the a-z range wildcard.
Type the following to filter out the metadata and display only the properties for the class.
Get-wmiobject –class win32_bios | format-list [a-g]*
In some cases, other cmdlets use WMI to return data (although often filtered in some fashion).
Now, compare the output from Get-Service to Get-WmiObject against the Netlogon
service:
Get-wmiobject Win32_Service| ?{$_.name –eq “netlogon”} | fl *
Name : Netlogon
Status : OK
ExitCode : 1077
DesktopInteract : False
ErrorControl : Normal
PathName : C:\Windows\system32\lsass.exe
ServiceType : Share Process
StartMode : Manual
AcceptPause : False
AcceptStop : False
Caption : Netlogon
CheckPoint : 0
CreationClassName : Win32_Service
DisplayName : Netlogon
InstallDate :
ProcessId : 0
ServiceSpecificExitCode : 0
Started : False
StartName : LocalSystem
State : Stopped
SystemCreationClassName : Win32_ComputerSystem
Microsoft Confidential
Page 275 of 361
SystemName : CONTOSO
TagId : 0
WaitHint : 0
Scope : System.Management.ManagementScope
Path : \\CONTOSO\root\cimv2:Win32_Service.Name="Netlogon"
Options : System.Management.ObjectGetOptions
ClassPath : \\CONTOSO\root\cimv2:Win32_Service
Properties : {AcceptPause, AcceptStop, Caption, CheckPoint...}
SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers : {dynamic, Locale, provider, UUID}
get-service netlogon | fl *
Name : Netlogon
RequiredServices : {LanmanWorkstation}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
DisplayName : netlogon
DependentServices : {}
MachineName : .
ServiceName : Netlogon
ServicesDependedOn : {LanmanWorkstation}
ServiceHandle : SafeServiceHandle
Status : Stopped
ServiceType : Win32ShareProcess
Site :
Container :
Both methods of access return data related to services, but the WMI object directly is far
more verbose.
To find out what other Classes are available to us, use the Get-WmiObject cmdlet to return
an entire list (this may take a minute to enumerate depending on machine speed).
PS:> Get-WmiObject -list
As you can see, there are more than a thousand default/base classes available for a wide
range of components. Additional classes are often included for different product lines such as
SharePoint, IIS and Exchange.
If you need information on methods, this code snippet will query WMI and extract all the
available methods for all classes.
PS:> Get-WmiObject -List * |
Where-Object{$_.Methods -ne $Null} |
Select-Object -ExpandProperty Methods |
Sort-Object Origin,Name |
Select-Object Origin,Name -Unique
Microsoft Confidential
Page 276 of 361
You will see that the information for win32_computer system is displayed.
2. In the PowerShell console, type the following command and press Enter.
Get-wmiobject –namespace root\cimv2 win32_computersystem
You will see that the information for win32_computer system is displayed. This is the
same as the information displayed when not specifying the namespace.
This information is important for two main reasons.
Although most of the information you will be working with will come from
root\cimv2, there are times that you may need to get information from other
namespaces. An example of this is the System Center Configuration Manager client
agent. The Client agent has its own WMI namespace, which can be used to trigger
client agent actions such as check for advertisements or perform software or
hardware inventory.
The other reason you should know about the -namespace parameter is because the
default namespace on the machine might change. While this is rare, if you are writing
scripts that rely on the default value and never check it or explicitly specify it, your
code could have errors. It is good practice to always specify the namespace in scripts,
to ensure you are addressing the correct namespace.
-class Parameter
The class parameter is a required parameter and the default parameter. This means that the
first value passed to the cmdlet will, by default, be assigned to the class parameter. The class
is the WMI class that you wish to obtain information from. For example, the following are
the same command:
Get-wmiobject win32_process
Get-wmiobject –class win32_process
Microsoft Confidential
Page 277 of 361
Similarly, always specifying the namespace parameter in scripts, is also a good practice to
specify the class parameter. This does not always apply to interactive console use, as it is
important to minimize the amount of typing done in the PowerShell console. However, the
parameter should always be used in scripts. So, for example, the following should be used in
a PowerShell script.
Get-wmiobject –namespace “root\cimv2” –class win32_process
-list Parameter
The -list parameter is used to list the available classes for a given namespace. If the
namespace is not specified then the default name space of root\cimv2 is used.
-computer Parameter
The -computer parameter is used to specify the computer to be queried. The parameter is
optional and the local computer is used unless specified otherwise. In the WMI query
language (WQL) that will be covered shortly, the local computer is referred to as a . You can
specify the parameter and use the . to ensure you are working against the local computer or
you can specify the NetBIOS, FQDN or even IP address of a remote machine to query.
For example,
Get-wmiobject –computer syddc01 –namespace root\cimv2 –class win32_share
-credential Parameter
Like several other cmdlets , the -credential parameter is used to allow the get-wmiobject
cmdlet to be run as another account. This parameter requires a PowerShell credential object.
If specified with the username, it will prompt for the password. This is typically used when
also specifying the -computername parameter.
For example,
$creds = get-credential
-EnableAllPrivileges Parameter
The -EnableAllPrivileges parameter is used to enable all privileges for the current user. This
is sometimes needed, as some special WMI privileges are used with some methods that are
not normally granted by default. The best example of this is the shutdown computer right. If
the -EnableAllPrivileges parameter is not specified, calling the method will fail.
Microsoft Confidential
Page 278 of 361
statements). If you reference the WMI SDK and look for the topic on WQL, you will find the
full list of keywords and operators available for WQL.
The basic structure of a WQL query is very similar to SQL.
<Select> | properties | <from> | class | <where>| filter criteria
The first two sections, the select and from are mandatory. The where section is optional.
You will notice that even though only the name, startmode and state properties have been
selected, using the format-list Cmdlet displays these properties as well as the WMI metadata
as the __ classes. This is unavoidable, as the WMI service will always return the metadata.
This can be dealt with in two ways.
It can be filtered from display using format-list [a-z]*. However, the data is still there.
It can be discarded by using the select-object Cmdlet and specifying the properties of
interest.
Microsoft Confidential
Page 279 of 361
Note the use of the double quotes inside the single quote string. This is due to the way the
Cmdlet and the query works. The reason for this is that the query needs to be a string in
PowerShell, while the query is actually a command for the WMI service. As such, the value
of netlogon needs to be passed to the WMI service as a string. The use of the double quotes
inside the single quotes allows for a string inside a string. It is also possible to use this in the
opposite way and have single quotes inside a double quote string. The latter is more common
as it allows for variables to be used and expanded inside the query string.
ExitCode : 0
Name : Netlogon
ProcessId : 604
StartMode : Auto
State : Running
Status : OK
Now, you are selectively targeting just the Netlogon service as part of the query. Only this
object is returned rather than a collection of all objects.
For a local query, the results will be very similar. However, there is an execution advantage
in getting the WMI query to perform the filtering. This is because the WMI service will be
performing the filtering. For a remote query, this is very important as the amount of data
retrieved from the WMI service and then transmitted over the network is very different. The
execution time is also affected. This is also very important in scripts, as you will often be
retrieving WMI information from multiple machines.
A major difference to be aware of when using WQL is the operators used in the where
section. The operators used here are WQL operators and not PowerShell operators. The
following are the WQL operators and their descriptions:
Operator Description
= Equal to
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to
!= or <> Not equal to
Is Is
Is not Is not
Like Wildcard match
There are two other things you need to be aware of with WQL, that are different from the
PowerShell language:
Microsoft Confidential
Page 280 of 361
The logic keywords available for use in the WQL language are the words AND and OR as
well round brackets (). The normal algebraic logic rules apply here, with both the use of the
keywords and the brackets.
ExitCode : 0
Name : Netlogon
ProcessId : 604
StartMode : Auto
State : Running
Status : OK
We get the same data set returned in either scenario. Using the -filter criteria may be
advantageous when only a small subset of data is desired (specific property) while the WQL
query is more robust.
Microsoft Confidential
Page 281 of 361
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : BIOS Date: 05/23/12 17:15:53 Ver: 09.00.06
SerialNumber : 5841-1807-8159-8121-4504-5660-30
Version : VRTUAL - 5001223Use the same command, but now executed against a
machine named syddc01
Get-WmiObject -Computername "syddc01" -Class Win32_Bios
SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : BIOS Date: 05/23/12 17:15:53 Ver: 09.00.06
SerialNumber : 5661-8327-5168-3547-0914-4161-08
Version : VRTUAL - 5001223The data returned from the local (Virtual) machine
differs from the data retrieved from the remote machine (in this case a different virtual
machine with a different serial number).
Microsoft Confidential
Page 282 of 361
TypeName: System.Management.ManagementObject#root\cimv2\Win32_Service
TypeName: System.Management.ManagementObject#root\cimv2\Win32_TerminalService
Note that the output has been modified for display purposes.
As you can see from the output, using get-member you can easily display the methods
available for a WMI class.
To execute one of these methods, there are a few things you need to remember. First, for
multiple instance classes, you need to isolate the results to a single instance to execute the
method on.
Second, you need to know how the method works. For each WMI class, and even each
WMI method, these can be very different. Just like a .NET class, you will need to
reference each WMI class and each method to know how they work. This is again in the
WMI SDK. In the example above, you used the win32_service class, which contains an
instance for each service on the system. For example, to be able to use the stopservice
method, you need to target just one service. For this example, you will use the BITS
server.
2. In the PowerShell console, type the following:
$bits = get-wmiobject –namespace “root\cimv2” –class win32_service –filter `
“name=’bits’”
Microsoft Confidential
Page 283 of 361
The code above assigns the BITS service object to the variable $bits, which allows you
to execute the method using the dot notation. You can do this as a single line using
brackets. However, keeping the variable creates a repeatable reference for the object.
The next step is to execute the method.
3. In the PowerShell console, type the following:
$bits.stopservice()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
You will notice that after executing the method, you will get return information from
WMI. The most important of this information is the return code. The return code is also
method and class specific so these need to be referenced. However, as a general rule, a
return code of zero is a success and any other return code is an error of some description.
For the StopService method, all the following are possible return codes.
Return Description Return Description
Code Code
0 Success 13 Service dependency failure
1 Not supported 14 Service disabled
2 Access denied 15 Service logon failed
3 Dependent services 16 Service marked for deletion
running
4 Invalid service control 17 Service no thread
5 Service cannot accept 18 Status circular dependency
control
6 Service not active 19 Status duplicate name
7 Service request timeout 20 Status - invalid name
8 Unknown failure 21 Status - invalid parameter
9 Path not found 22 Status - invalid service account
10 Service already stopped 23 Status - service exists
11 Service database locked 24 Service already paused
12 Service dependency
deleted
As you can see, the return codes can contain a lot of useful status information.
Microsoft Confidential
Page 284 of 361
Now, in this circumstance, you have changed the status of the bits service from running
to stopped. Check out the results
In the PowerShell console, type the following:
$bits
ExitCode : 0
Name : BITS
ProcessId : 1052
StartMode : Auto
State : Running
Status : OK
Clearly, the output appears incorrect? The output using the variable reference shows that
the service is still running − and this is after you have executed the stopservice method
and got a return code of 0 for success. The issue here is that the data in the $bit variable
is not dynamic. Therefore, because WMI is a query-based system the information stored
in the $bit reference is the status at the time of assignment to the variable. If you want to
look at the current status, you need to run the query and assignment again.
4. Type the following in the PowerShell console to execute the query and assignment again.
$bits = get-wmiobject –namespace “root\cimv2” –class win32_service –filter
“name=’bits’”
ExitCode : 0
Name : BITS
ProcessId : 1052
StartMode : Auto
State : Stopped
Status : OK
The stopservice method does not require any parameters to be passed when using the
method call. However, there are other methods that require parameters to be passed.
Now, look at another common method that you might use when managing services with
WMI. This is the changestartmode method. This method allows you to change the start
mode of the server. There are several types of start modes that can be set. By specifying
this, the startmode will be changed accordingly.
To use the parameter in PowerShell, like all other methods, use a string with the value
from the table. An advantage of this WMI class is that the return codes for this method
are the same as the return codes for the stopservice method.
Below are the parameters for the changestartmode method:
Value Meaning
Boot Device driver started by the operating system loader. This value
is valid only for driver services
Microsoft Confidential
Page 285 of 361
Now, change the start mode of the bits service from Auto to manual.
6. In the PowerShell console type the following:
$bits.changestartmode(“manual”)
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
To get the current status of the service after the change you can either re-execute the
query, or execute a new one.
7. In the PowerShell console, type the following to check the current status.
Get-wmiobject –namespace “root\cimv2” –class “win32_service” –filter “name=’bits’”
ExitCode : 0
Name : BITS
ProcessId : 1052
StartMode : Manual
State : Stopped
Status : OK
Microsoft Confidential
Page 286 of 361
Microsoft Confidential
Page 287 of 361
As you can see from the classes in the table, a large amount of system information is covered
by these classes. While these will not exclusively be the WMI classes you will use, they will
contain most of the information that you need as a systems administrator.
Now you will look as some of the classes that have not been dealt with already.
Microsoft Confidential
Page 288 of 361
Below is an example of building the WMI ping into a function. The examples also include a
function to look up the result code from the query and display the description for the return
code.
8. Open the ISE and enter the following code:
#functions
Function wmiping($strcomputername)
{
$strQuery = "select * from win32_pingstatus where address = '" +
$strcomputername + "'"
$wmi = Get-WmiObject -Query $strQuery
Write-Host "Pinging $strcomputername ... "
if ($($wmi.statuscode) -eq $null)
{
$rtnvalue = $($wmi.PrimaryAddressResolutionStatus)
}
else {$rtnvalue = $($wmi.statuscode)}
return $rtnvalue
}
Function pingerror($errcode)
{
switch ($errcode)
{
11001 {$errdetails = "Buffer Too Small"}
11002 {$errdetails = "Destination Net Unreachable"}
11003 {$errdetails = "Destination Host Unreachable"}
11004 {$errdetails = "Destination Protocol Unreachable"}
11005 {$errdetails = "Destination Port Unreachable"}
11006 {$errdetails = "No Resources"}
11007 {$errdetails = "Bad Option"}
11008 {$errdetails = "Hardware Error"}
11009 {$errdetails = "Packet Too Big"}
11010 {$errdetails = "Request Timed Out"}
11011 {$errdetails = "Bad Request"}
11012 {$errdetails = "Bad Route"}
11013 {$errdetails = "TimeToLive Expired Transit"}
11014 {$errdetails = "TimeToLive Expired Reassembly"}
11015 {$errdetails = "Parameter Problem"}
11016 {$errdetails = "Source Quench"}
11017 {$errdetails = "Option Too Big"}
11018 {$errdetails = "Bad Destination"}
11032 {$errdetails = "Negotiating IPSEC"}
11050 {$errdetails = "General Failure"}
# Main code
cls
do
{
Write-Host "This script will ping an IP address or machine name"
Microsoft Confidential
Page 289 of 361
Microsoft Confidential
Page 290 of 361
Objectives
After completing this lab, you will be able to:
Describe the core WMI concepts in Windows
Leverage the Get-WMIObject cmdlet to access WMI from within PowerShell
Review some of the most commonly used WMI classes
Discover gathering data remotely using Get-WMIObject
Filter and sort returned WMI data
Provide best practices when leveraging WMI in scripting
Prerequisites
A Windows 7 workstation logged in with administrator credentials
A Windows 2008 server logged in with administrator credentials
Microsoft Confidential
Page 291 of 361
Scenario
Now that you have seen how to access WMI in Windows, you can use PowerShell 1.0 or 2.0
to get information from it.
At this time, your focus will be on getting only local information.
Microsoft Confidential
Page 292 of 361
This is the basic Cmdlet to enumerate the contents of a WMI Class. You provide only the
Class Name; all the other parameters have good defaults.
This WMI class, win32_quickfixengineering, will display the current applied hotfixes
on a system.
2. In the PowerShell console, run the following to reformat the data.
Get-wmiobject –class “win32_quickfixengineering” | format-table hotfixid,
description, installedby, installedon
You will now see that the source column is no longer displayed and the KB number is
now the first column displayed.
3. Type the following into the PowerShell console to export the list of hotfixes to a text file.
Get-wmiobject –class “win32_quickfixengineering” | select-object hotfixid,
description, installedby, installedon > hotfixes.txt
Now examine the text file produced. You will see that it contains the list of the hotfixes.
Question A: notepad .\hotfixes.txtWhy was select-object used instead of format-
table in the example above?
Answer: Select object was used as it discards any additional data aside from the
specified properties. Format-table on the other hand is for formatting the information
displayed in the PowerShell console.
4. Type the following in the PowerShell console to export the list of hotfixes to a .CSV file.
Get-wmiobject –class “win32_quickfixengineering” | export-csv hotfixes.csv `
-notypeinformation
Microsoft Confidential
Page 293 of 361
Scenario
One very useful WMI class is the win32_networkadapterconfiguration class. This class
however needs to be filtered to get the useful information out. This is common with many
WMI classes.
Microsoft Confidential
Page 294 of 361
You will now see a long list of network adapters available on the system. Some of these
include the RAS adapters, the WAN mini port and other such adapters. For most
purposes, you are not concerned or interested in these adapters. However if you were
there is lots of information available for these.
Most of the time you will be interested in the adapter that contains a valid IP address as
this will be the active NIC that is being used. To look at this adapter, you need to filter
out the other adapters.
Question B: Based on the information displayed, what is the property that offers
the easiest way to filter network adapters?
Answer : From what is displayed, the IP address will be the easiest way to filter the
network adapters.
2. In the PowerShell console, type the following command to filter the network adapters:
Get-wmiobject –namespace “root\cimv2” –class win32_networkadapterconfiguration |
where-object {$_.ipaddress –ne $null}
This will filter the network adapters down to just the NICs that have an IP address.
However, you are aware that using where-object is not the most effective way of
filtering WMI instances.
The IPAddress property is a little tricky. This property is an array property, since a NIC
can have multiple IP Addresses, although this is not very common. Therefore, querying
this property for a NULL value will not work. Instead, look at all the properties available
for the network adapter.
3. In the PowerShell console, type the following to display all the information for the
network adapter with an IP address.
Get-wmiobject –namespace “root\cimv2” –class win32_networkadapterconfiguration |
where-object {$_.ipaddress –ne $null} | format-list *
You will see all the properties for the network adapter displayed. Examine this
information and look at the properties. One of these properties will let you know if the
network adapter has an IP address.
Question C: What is the property that lets you know if the network adapter has an
IP Address?
Answer: The property is IPEnabled.
Now that you have found the property IPEnabled, you can use it in a WMI query or
filter to get just the NIC or NICs with IP Addresses.
Microsoft Confidential
Page 295 of 361
4. In the PowerShell console, run the following command to filter using a WMI query.
Get-wmiobject –query “select * from win32_networkadapterconfiguration where
ipenabled = ‘true’ “
You will see the information displayed is the same using either method. It is a matter of
preference as to which you will use.
6. In the PowerShell console, run the following command to display all the information for
the WMI class instance.
Get-wmiobject –namespace “root\cimv2” –class win32_networkadapterconfiguration `
–filter “ipenabled = ‘true’ ” | format-list [a-z]*
Microsoft Confidential
Page 296 of 361
Scenario
When working with WMI classes and information it is possible to not only obtain
information, but also to make changes using WMI methods. In this exercise you will execute
some methods on the win32_networkadapterconfiguration class.
The DNS servers and gateway properties will now be in the list of properties. You will
now use WMI ping to verify that these values are correct.
2. Run the following command to test the first DNS server:
Microsoft Confidential
Page 297 of 361
Where <DNS SERVER> is the IP address of the DNS server from the first query in the
DNSServerSearchOrder property.
Question A: Did the query return a success or a failure?
Answer: The first DNS server will ping successfully.
3. Repeat the command from step 2 but replace it with a second DNS server.
Get-wmiobject –query “select * from win32_pingstatus where address=’<DNS SERVER>’”
| ft ipv4address, statuscode -autosize
Where <DNS SERVER> is the IP address of another DNS server from the first query in
the DNSServerSearchOrder property.
Question B: Question? Did the query return a success or a failure?
Answer: The second DNS server will not ping successfully, as it is not online in the
lab environment.
Now you will test the gateway to verify that it is correct.
4. Type the following command to verify the default gateway address.
Get-wmiobject –query “select * from win32_pingstatus where address=’<DEFAULT
GATEWAY>’” | ft ipv4address, statuscode -autosize
Where <DEFAULT GATEWAY> is the IP address of the default gateway from the first
query.
Question C: Question? Did the query return a success or a failure?
Answer: The default gateway server will ping successfully.
Now that the DNS servers and default gateway addresses have been verified, you can now
use WMI methods to modify these values.
Microsoft Confidential
Page 298 of 361
Now that the active network is assigned to the variable, you can easily execute the
method. However, just before you do that, verify that the variable contains the network
adapter of interest.
2. Run the following command to list the active network adapter:
$mynic
Note: If you do not see the active network adapter listed, then there is something
wrong with the query.
Now you are ready to set the DNS servers and the search order. The
setDNSServerSearchOrder method will accept an array of strings for the DNS servers.
If you are setting a single DNS server (which is not best practice) then you can use a
string for the single DNS server − PowerShell will convert this to an array for the method
execution.
However if you are going to set multiple DNS servers and the search order, then you
need to supply an array of strings. The easiest way to do this is to create a variable with
the array of strings and then use this variable in the method call.
3. Run the following command to set the single DNS server value:
$mynic.SetDNSServerSearchOrder(“192.168.0.1”)
The return code should be zero indicating that the value has been changed. To verify the
result, you need to run the query again, as $mynic will reflect the configuration as the
time of assignment.
Get-wmiobject –query “select * from win32_networkadapterconfiguration where
ipenabled = ‘true’ “ | format-list *
You will now see that the DNS servers have changed and will only be a single address. If
this is not the case, then look at the method call and result code to determine what has
gone wrong.
Now you will use a similar method to clear the current gateway value.
Microsoft Confidential
Page 299 of 361
The default gateway should now be blank in the adapter properties or 0.0.0.0 under
PowerShell.
Now you need to set the value of this back to the previous value.
3. Run the following command to set the gateway value:
$mynic.setgateways(“192.168.0.1”)
4. Run the following command to verify the gateway has been changed:
Get-wmiobject -query "select * from win32_networkadapterconfiguration where
ipenabled = 'true'"
Microsoft Confidential
Page 300 of 361
Microsoft Confidential
Lesson 10 Demonstration : Registry, Event Log and
ACL Management
Introduction
In the previous modules, you have learned about Windows Powershell fundamentals along
with WMI and Active Directory management.
The other important Windows constituents that administrators commonly manage are system
Registry, Event Logs and Access control lists (ACL) on the registry or file system.
Windows Powershell offers a cluster of cmdlets to manage Event Logs and ACLs.
The Registry provider lets you get, add, change, clear, and delete registry keys and values in
Windows PowerShell.
In addition, most of these integral components of Windows can also be managed using
Windows Powershell through select .Net and WMI classes.
Objectives
After completing this lab, you will be able to:
Manage the registry using the registry provider.
Access Remote registry using Windows Powershell.
Manage Event Logs and file system ACLs using Windows Powershell cmdlets.
Prerequisites
Windows 2008 server and Windows 7 workstation logged on to with domain administrator
credentials.
Microsoft Confidential
Page 302 of 361
Scenario
The Windows Powershell registry provider simplifies access to the registry by exposing the
hives as drives.
The registry provider provides access to the local registry keys and values. The registry
provider can be used to access a remote machine’s registry if used within a PS v2.0 Remote
session.
The Registry Provider allows us to access two PS Drives:
HKCU (HKEY_CURRENT_USER)
HKLM (HKEY_LOCAL_MACHINE)
The following command lists the PS Drives offered by the registry provider.
PS C:\> get-PSProvider registry
In order to manage the registry items exposed by the provider, the following cmdlets are
designed to work with the data.
Name Synopsis
Clear-ItemProperty Deletes the value of a property but does not delete the property
Copies a property and value from a specified location to another
Copy-ItemProperty location
Get-ChildItem Gets the items and child items in one or more specified locations
Get-ItemProperty Gets the properties of a specified item
Move-ItemProperty Moves a property from one location to another
Get-Item Gets the item at the specified location
New-Item Creates a new item
Microsoft Confidential
Page 303 of 361
For example, in the drives that are supported by the Registry provider, you can use New-Item
to create a new registry key.
In the following sections of this exercise, we will demonstrate the following operations using
the registry provider:
Navigating the registry
Testing key existence
Reading registry properties
Creating registry keys
Creating registry properties
Modifying registry properties
3. List the sub keys in the HKCU hive using Dir or GCI.
PS HKCU:\> dir
Hive: HKEY_CURRENT_USER
Microsoft Confidential
Page 304 of 361
SKC VC Name
--- -- ----
2 0 AppEvents
2 37 Console
.. ..
4. You can set the location (cd/sl) to any registry key as follows:
PS HKCU:\> cd software\microsoft\windows\currentversion\explorer
PS HKCU:\software\microsoft\windows\currentversion\explorer>
5. Similarly, you can directly set the location to a key in any of the registry providers
(HKLM: in the below command) from any other PS Drive.
PS HKCU:\> cd HKLM:\software\microsoft
PS HKLM:\software\microsoft>
Hive: HKEY_LOCAL_MACHINE\software\microsoft\windows
Unlike Get-ChildItem, using get-item does not enumerate the sub keys, but only returns
the target Registry key.
PS HKLM:\> Get-Item hklm:\software\microsoft\windows
Hive: HKEY_LOCAL_MACHINE\software\microsoft
2. To recursively search a registry key, the parameters –recurse and –include can be used as
follows:
PS HKLM:\> Get-childitem HKLM:\software -recurse -include Windows
This will find all the keys that contain the word "Windows" in the key names.
3. The Registry item returned, correspond to Microsoft.Win32.RegistryKey object that
provides the following associated member types.
PS HKLM:\> Get-item hklm:\software\microsoft\windows | Get-Member
Microsoft Confidential
Page 305 of 361
TypeName: Microsoft.Win32.RegistryKey
5. To check if a Registry sub Key exists, you can also use the containment operator -
contains.
PS HKLM:\> (Get-item hklm:\software\microsoft\windows).getsubkeynames() -contains
"windows search"
Microsoft Confidential
Page 306 of 361
True
PS HKLM:\>
In the above example, the output returns TRUE because the sub key named “Windows
Search” exists in the target parent key.
PSPath:Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\P
owerShell\1
PSParentPath:Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Micro
soft\PowerShell
PSChildName: 1
PSDrive: HKLM
PSProvider: Microsoft.PowerShell.Core\Registry
Install: 1
PID: 89383-100-0001260-04309
PS HKLM:\>
In the above output, you will notice that along with the registry values in the key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1, few of the
Powershell properties are also returned.
2. If you would like to determine the data contained in a particular value, use the value
name (as a) property in the output shown in the previous step.
In the following example, the data in the value named PID is obtained.
PS HKLM:\> $Regvalues= GP HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1
PS HKLM:\>$regvalues.pid
89383-100-0001260-04309
PS HKLM:\>
3. As shown below, you can also return the value data using the getvalue method on the key.
PS HKLM:\> (Get-Item HKLM:\SOFTWARE\Microsoft\PowerShell\1).getvalue("pid")
89383-100-0001260-04309
PS HKLM:\>
Hive: HKEY_CURRENT_USER\software
Microsoft Confidential
Page 307 of 361
PS HKLM:\>
2. The following syntax using the parameters –path and –name will create a registry key
named “OurApplication".
PS HKLM:\> new-item -Path hkcu:\software -Name OurApplication
Hive: HKEY_CURRENT_USER\software
PS HKLM:\>
3. Alternatively, you can also run the following commands from the local path to create a
registry key.
PS HKCU:\software> New-Item yourApplication
Hive: HKEY_CURRENT_USER\software
PS HKCU:\software>
Or,
PS HKCU:\software> New-Item -Path . -Name hisApplication
Hive: HKEY_CURRENT_USER\software
PS HKCU:\software>
For more information on how to use Remove-Item, obtain help on the cmdlet (help
remove-item –full)
Microsoft Confidential
Page 308 of 361
Note: This cmdlet does not add properties to an object. To add a property to an
instance of an object, use the Add-Member cmdlet. To add a property to all objects of a
particular type, edit the Types.ps1xml file.
2. Enter the command below to create a DWORD property named ‘Config1’ with a value of
‘1024’ in the registry key ‘MyApplication’.
PS HKLM:\> New-ItemProperty HKCU:\Software\MyApplication -name "Config1" -value
"1024" -propertyType DWORD
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\MyApplication
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software
PSChildName : MyApplication
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
Config1 : 1024
PS HKLM:\>
The code above assumes that the registry key ‘MyApplication’ exists prior to running the
command.
If the parameter -propertyType is not used, the registry value created will be of the data
type REG_SZ.
For more information on how to use Remove-ItemProperty, obtain help on the cmdlet
(help remove-itemproperty –full)
If the DWORD property did not pre-exist, a new REG_SZ property with the value of
“2048” would have been created.
Microsoft Confidential
Page 309 of 361
2. The parameter–force used with New-ItemProperty can also set/overwrite the value of an
existing registry property retaining its data type.
For example:
PS HKLM:\> New-ItemProperty –path HKCU:\Software\MyApplication -name "Config1" -
value "4096" -force
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\MyApplication
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software
PSChildName : MyApplication
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
Config1 : 4096
PS HKLM:\>
Microsoft Confidential
Page 310 of 361
Scenario
In the previous exercise, we have learned how to access the local registry using the Windows
Powershell registry provider.
Though PowerShell 2.0 Remoting is the easiest way to deal with remote registry access, it
will only work in environments with PowerShell v2.0 installed and Windows Remote
Management (WINRM) allowed on the remote machines.
In this exercise, we will explore remote registry management using the Microsoft .Net
Framework Microsoft.Win32.Registry class.
Microsoft Confidential
Page 311 of 361
TypeName: Microsoft.Win32.RegistryKey
The following sections of this exercise will cover the usage of the commonly used
methods and demonstrate the following remote registry operations:
Navigating the registry
Testing key existence
Reading registry properties
Creating registry keys
Creating registry properties
Modifying registry properties
Microsoft Confidential
Page 312 of 361
The above variable stores information about the HKLM registry hive of the remote
computer “Syddc01”.
3. You can connect to any accessible sub key using the opensubkey() method
PS C:\> $dotnetreg = $RemoteReg.OpenSubKey("Software\Microsoft\NET Framework
Setup\NDP\v2.0.50727")
PS C:\> $dotnetreg
The opensubkey() method requires the subkey path parameter as a shown above.
PS C:\> $RemoteReg.GetSubKeyNames()
BCD00000000
HARDWARE
SAM
SECURITY
SOFTWARE
SYSTEM
PS C:\>
2. To determine the existence of a key, you can use the where-object filter on the list of
returned subkey names.
PS C:\> $psreg = $RemoteReg.OpenSubKey("SOFTWARE\Microsoft\PowerShell\1")
Microsoft Confidential
Page 313 of 361
PS C:\>
2. If you would like to determine the data value contained in a particular property, use the
GetValue() method with the property name as a parameter to the method.
In the following example, the data in the property named PID is obtained.
PS C:\> $psreg.GetValue("pid")
89383-100-0001260-04309
PS C:\>
3. The following code lists all the registry value names and their associated data at a time
using the Foreach-Object loop.
PS C:\> $psreg.GetvalueNames() | foreach-object { "$_ : $($psreg.getvalue($_))"}
Install : 1
PID : 89383-100-0001260-04309
PS C:\>
2. While using the OpenSubKey() method, provide the optional Boolean argument to open
the subkey in R/W mode. However, it is always necessary to specify $true if you want to
add, delete, or modify values or keys in a particular registry hive.
In the following steps, a subkey will be created inside the target key
“\Software\Microsoft”.
PS C:\> $MSReg = $RemoteReg.OpenSubKey("Software\Microsoft”, $true)
PS C:\>
3. Use the createsubkey() method to create a sub key in the target key
“\Software\Microsoft”.
PS C:\> $MSReg.CreateSubKey("MSData")
Microsoft Confidential
Page 314 of 361
2. To create registry values of different data types use the method Setvalue() on the target
RegistryKey object.
PS C:\> $MSDataReg.setvalue("State", "1", "Dword")
PS C:\>
If the data type argument (third place) to the setvalue() method is not passed, the registry
value created will be of the type REG_SZ.
Note: Use the method deletevalue() to delete a registry property on the RegistryKey
class object.
Microsoft Confidential
Page 315 of 361
Scenario
Event Logs are special files that record significant events on your computer, such as, when a
user logs on to the computer or when a program encounters an error.
Starting with Windows Vista and Windows Server 2008 onwards, the operating system
includes two categories of event logs:
Windows Logs
Applications and Services logs
Microsoft Confidential
Page 316 of 361
To get events from logs that use the Windows Event Log technology in Windows Vista and
later versions of Windows, use Get-WinEvent, which is discussed in the next section of the
exercise.
1. Enter the following command to list the cmdlets that contain the EventLog noun.
PS C:\> gcm *-eventlog -CommandType cmdlet
CommandType Name
----------- ----
Cmdlet Clear-EventLog
Cmdlet Get-EventLog
Cmdlet Limit-EventLog
Cmdlet New-EventLog
Cmdlet Remove-EventLog
Cmdlet Show-EventLog
Cmdlet Write-EventLog
Note: All of the above cmdlets can be used with the –computer parameter to manage
remote Windows event logs.
In the following examples, the common Event Log management scenarios will be
covered.
Read Windows Event Logs
1. On the windows task bar, locate and click the icon. This will open the Windows
Powershell menu.
2. At the PS prompt, enter the following command to list the Windows event logs on the
machine.
PS C:\> Get-EventLog -list
Microsoft Confidential
Page 317 of 361
3. The command below lists the last 5 ‘Netlogon’ errors reported in the System event log.
PS C:\> get-eventlog -newest 5 -logname System -entrytype Error –Source Netlogon
Similarly, the other Windows event logs listed in Step (2) can be queried.
Write an event to an Event Log
If for instance, your script would like to write a log on the local or remote computer in the
event of a failure or success of an operation, the cmdlet, Write-EventLog, can be useful.
4. Enter the following command to write an Application Event Log with Event ID 10005
and Source VSS.
PS C:\> write-eventlog -logname Application -source VSS -eventID 10005 -entrytype
Warning -message "Unable to copy the backup. For help contact your system
administrator"
The above syntax will clear the Application and System event logs from the remote
computer named ‘syddc01’.
2. The Get-Winevent cmdlet provides more information on the event log properties.
PS C:\> get-winevent -listlog System | format-list -property *
FileSize : 16912384
IsLogFull : False
LastAccessTime : 6/24/2011 5:53:56 PM
LastWriteTime : 10/5/2011 11:02:23 AM
OldestRecordNumber : 147781
RecordCount : 40761
Microsoft Confidential
Page 318 of 361
LogName :
System
LogType :
Administrative
LogIsolation :
System
IsEnabled :
True
IsClassicLog :
True
SecurityDescriptor :
O:BAG:SYD:(A;;0xf0007;;;SY)(A;;0x7;;;BA)(A;;0x
;;;SU)(A;;0x1;;;S-1-5-3)(A;;0x2;;;S-1-5-33)(A;
LogFilePath : %SystemRoot%\System32\Winevt\Logs\System.evtx
MaximumSizeInBytes : 15532032
LogMode : Circular
OwningProviderName :
ProviderNames : {ACPI, adp94xx, adpahci, adpu320...}
ProviderLevel :
ProviderKeywords :
ProviderBufferSize : 64
ProviderMinimumNumberOfBuffers : 0
ProviderMaximumNumberOfBuffers : 16
ProviderLatency : 1000
ProviderControlGuid :
As specified in the –maxevents parameter, the output above will return a maximum of 10
events only.
4. Enter the following command to list the providers that write to the System log.
PS C:\> (get-winevent -listlog System).providernames
TypeName: System.Diagnostics.EventLogEntry
Name MemberType
---- ----------
Category Property
CategoryNumber Property
Container Property
Data Property
EntryType Property
Index Property
InstanceId Property
MachineName Property
Message Property
ReplacementStrings Property
Site Property
Source Property
TimeGenerated Property
Microsoft Confidential
Page 319 of 361
TimeWritten Property
UserName Property
TypeName: System.Diagnostics.Eventing.Reader.EventLogRecord
Name MemberType
---- ----------
ActivityId Property
Bookmark Property
ContainerLog Property
Id Property
Keywords Property
KeywordsDisplayNames Property
Level Property
LevelDisplayName Property
LogName Property
MachineName Property
MatchedQueryIds Property
Opcode Property
OpcodeDisplayName Property
ProcessId Property
Properties Property
ProviderId Property
ProviderName Property
Qualifiers Property
RecordId Property
RelatedActivityId Property
Task Property
TaskDisplayName Property
ThreadId Property
TimeCreated Property
UserId Property
Version Property
PS C:\>
The command above will search the System log for source ‘Time-Service’ that has an
Event ID ‘129’ and contains the “not found” message description.
4. Using the –FilterHashTable parameter with Get-WinEvent cmdlet.
This uses a query in hash table format to select events from one or more event logs.
Run the commands below to filter the ‘Windows Powershell’ logs for Event Id 400
logged since the previous day.
C:\PS> $yesterday = (get-date) - (new-timespan -day 1)
C:\PS> get-winevent -FilterHashTable @{LogName='Windows PowerShell'; id=’400’;
StartTime=$yesterday}
Microsoft Confidential
Page 320 of 361
Scenario
The file and folder access authorization is controlled using an access control list (ACL) on the
object. The ACL is a list of entries (called the Access Control Entry: ACE) that identifies
trustees and specifies the access rights allowed, denied, or audited for those trustees.
In easier terms, the ACL specifies the permissions that users and user groups have to access
the resource.
Several commands line utilities like cacls, xcacls, icacls can be used to verify and modify the
access permissions on files and directories.
Windows PowerShell uses the cmdlets, Get-Acl und Set-Acl, to manage the permissions.
Microsoft Confidential
Page 321 of 361
Note: The folders named Source and Destination need to be created with different
set of permissions before following the below steps.
1. Use the get-acl cmdlet to store the ACL of the source directory in a variable.
$sourceacl = Get-acl c:\Source
2. Next apply the ACL in $sourceacl to the destination directory by running the following
command.
Set-acl –path c:\destination –aclObject $sourceacl
3. Set the access rule object $aclRule to the existing access rule object $destacl using the
SetAccessRule() method.
PS C:\> $destacl.setaccessrule($aclrule)
4. Hence, the command below will apply the modified ACL to the destination folder.
PS C:\> Set-ACL c:\destination –aclobject $destacl
Microsoft Confidential
Page 322 of 361
Prerequisites
The lab requires a windows 7 client running in a domain environment.
Microsoft Confidential
Page 323 of 361
Duration
15 minutes
On the windows task bar, locate the icon. Click this icon.
The PowerShell window will open.
Microsoft Confidential
Page 324 of 361
$regkey = $reg.opensubkey($regpath)
Note: The parameter is added to the command to allow the key to be written to.
Microsoft Confidential
Page 325 of 361
The line above will create the registry key if it does not already exist.
The line above will extract as text the value of the serial number in bios.
7. On the next line, enter the following code.
$contoso.SetValue("serialnumber",$serialnumber)
The line above will create the registry value, serial number, and the value will be the
value in the $serialnumber variable.
8. On the next line, enter the following lines of code.
$values = $contoso.getvaluenames()
write-host "$server has the registry key HKLM:\software\Contoso if it didnt
already"
write-host "The following registry values exist under this key"
12. The following two lines of code should complete the script.
}
}
Microsoft Confidential
Page 326 of 361
Duration
15 minutes
On the windows task bar, locate the icon. Click this icon.
The PowerShell window will open.
The variables above will be used to store the paths to the files where error events from
the system log and application will be written.
4. On the next line, enter the following.
$sysevents = get-winevent –logname system | where-object {$_.id –eq 12} | select-
object –first 1 –property timecreated
The line above will search the eventlog for event ID 12, which is the operating system
started. The select-object cmdlet using the –first parameter gets the last occurrence on
this. This event ID can be used as a flag for the last boot as far as Eventlog entries go.
5. On the next line, enter the following.
$lastreboot = $($sysevents.timecreated)
The line above extracts the time on the startup event. This will be used in the following
lines to search for events after that time.
6. On the next line, enter the following.
Microsoft Confidential
Page 327 of 361
The line above will search the system log for any errors that have occurred after the time
in $lastreboot.
7. On the next line, enter the following.
$count = ($sysevents | Measure-Object).count
This will complete the if statement and else section. The code above will not only search
for error in the system log, but will also export them to a csv file. If there are no errors
then this will also be indicated.
17. Save your script and execute it in PowerShell.
You will see that script will run and inform you of any errors that are in the system log.
Note: You may not find any errors in the system after reboot. If you don’t see any errors
detected then check the system log to see if this is actually the case.
Microsoft Confidential
Page 328 of 361
18. Open the c:\pshell\part1\lesson10\labs\systemerrors.csv using notepad. You will see the
details of the event log entries in this file.
19. Open the script again in notepad or the ISE.
20. Copy the following lines of code.
$sysevents = get-winevent -logname system | where-object {$_.Timecreated -gt
$lastreboot} | where-object {$_.LevelDisplayName -eq 'Error' -or
$_.leveldisplayname -eq 'Critical'}
$count = ($sysevents | Measure-Object).count
If ($count –gt 0)
{
Write-host “$count Errors were found in the system eventlog. Details in
the file $systemerrors”
$sysevents | export-csv $systemerrors -notypeinformation
}
else
{
Write-host “No errors were found in the system eventlog after bootup at
$lastreboot”
}
The above code should now look at the application log for Critical or Error levels since
the last reboot.
23. Save your script and execute it in PowerShell.
You will see that script will run and inform you of any errors that are in the system log.
24. Open c:\pshell\part1\lesson10\labs\apperrors.csv using notepad. You will see the details
of the event log entries in this file.
Microsoft Confidential
Page 329 of 361
Note: You will need new variables and files to store the warning events in.
Microsoft Confidential
Page 330 of 361
Duration
15 minutes
On the windows task bar, locate the icon. Click this icon.
The PowerShell window will open.
This will create a new folder off the root of the C drive. This folder will inherit the
default permissions.
2. In Windows explorer, check the folder permissions by right-clicking the folder, selecting
Properties and checking the Security tab.
Note: The permissions of the built in users group will have read and execute, list folder
contents and read. These are inherited permissions so the ticks are grey.
This will read the access control lists for the object and assign them to the $acl variable.
4. Enter the following command.
$acl.access
This will now display the access control lists for users and their permissions.
In order to be able to change permissions such as removing a user from access, you need
to remove the inherence from the parent folder.
Microsoft Confidential
Page 331 of 361
The above command modifies the access control list, however, this is not applied to the
folder. To do this, you must set the ACL back to the folder.
2. Enter the following command to apply the modified ACL to the folder.
$acl | set-acl c:\userdata
Note: The permission ticks are now solid black. This indicates that the permissions are
set on the folder level and not inherited.
Now you will have the current acl’s in the $acl variable. Now we can remove a specific
users permissions from the object. First you must get the specific user ACL.
2. Enter the following command to get the BUILTIN\users ACL.
$useracl = $acl.access | where {$_.identityreference -eq "BUILTIN\Users"}
4. Enter the following to remove the ACL from the ACL list.
$acl.RemoveAccessRule($useracl)
This will remove the builtin\users acl from the list of ACL’s. Once this is done the ACL
list in the $acl variable can be applied to the object.
5. Enter the following to view the ACL list.
$acl.access
7. In Windows explorer, check the folder permissions by right-clicking the folder, selecting
Properties and checking the Security tab.
Note: The builtin\users group is now removed from the permission’s of the folder and
now, you will grant the BUILTIN\users group full control to the folder.
Microsoft Confidential
Page 332 of 361
The values for this can be 0 for none, 1 for containerinherit and 2 for ObjectInherit. The
value used above is 3, which is both container and object inherit.
2. Enter the following to set the propagation options for the folder.
$propagation = 0
The values for this can be 0 for none, 1 for NoPropagateInherit and 2 for Inheritonly.
The value used above is 0, which is none.
3. Enter the following to create an array for the new ACL.
$newacl = "BUILTIN\Users","fullcontrol",$inheritance,$propagation,"allow"
The above is an array of strings. This specifies the user account, the permissions required,
the inheritance and propagation flags and finally if the permissions are allowed or denied.
4. Enter the following to create the new ACL object.
$accessrule = new-object
system.security.accesscontrol.filesystemaccessrule($newacl)
5. Enter the following command to add the new ACL object to the ACL list.
$acl.AddAccessRule($accessrule)
8. In windows explorer, check the folder permissions by right-clicking the folder, selecting
Properties and checking the Security tab.
You will note that the BUILTIN\Users will now have full control of the folder.
Microsoft Confidential
Page 333 of 361
Microsoft Confidential
Page 334 of 361
Objectives
After completing this lesson you will be able to:
Understand remote management without PowerShell remoting
Understand PowerShell remoting and WS-Management
Understand remoting requirements and configuration
Use the invoke-command for executing one-off commands
Work with PowerShell sessions to:
Use a persistent remote session for executing a series of commands
Use an interactive remote session
Create a session configuration
Use background jobs with remoting
Understand remoting security and authentication, including:
Active directory group policy object settings
Kerberos, Negotiate, CredSSP and Basic authentication
Traffic Encryption
Prerequisites
A windows 7 workstation logged onto with administrator credentials
A domain controller, SYDDC01
Microsoft Confidential
Page 335 of 361
Scenario
In this exercise, you will understand remote management without the use of PowerShell
remoting. This can be very useful in the environment where PowerShell remoting is not
enabled.
This command lists all commands that contain the ComputerName parameter. It
excludes any command that also contains ‘Session’ as a parameter. The Session
parameter is associated with commands that relate to PowerShell remoting. The
objective of this exercise is to perform remote management without the use of the
PowerShell remoting feature.
Microsoft Confidential
Page 336 of 361
This command returns the ten newest events in the system event log on the domain
controller machine (SYDDC01).
2. Type the following command.
get-hotfix -computername syddc01,w7client
This command returns all the hotfixes on both the domain controller (SYDDC01) and
the Windows 7 client.
The first command creates a servers.txt file in the current users documents directory
using the $home automatic variable. The second command returns all the hotfixes on
both the syddc01 and w7client machines. The get-content Cmdlet is used to retrieve
the machine names from a text file in this example.
Microsoft Confidential
Page 337 of 361
Note: Either the machine name or IP address can be specified as the parameter
arguments for the ComputerName parameter.
Microsoft Confidential
Page 338 of 361
Scenario
PowerShell remoting is useful for running commands or scripts that do not have built-in
remote management capabilities. PowerShell remoting allows you to remotely manage
machines using the underlying Web Services for Management (WS-Management)
protocol implemented in the WinRM service.
WS-Management is an industry standard management protocol based on the Simple
Object Access Protocol (SOAP). The WS-Management protocol was developed by a
group of hardware and software manufacturers as a public standard for remotely
exchanging management data with any computer device that implements the protocol.
WinRM 2.0 is Microsoft implementation of the WS-Management protocol.
Microsoft Confidential
Page 339 of 361
Note: Windows PowerShell Integrated Scripting Environment (ISE) and the Out-
Gridview Cmdlet require the Microsoft .NET Framework 3.5 with Service Pack 1.
The Get-WinEvent cmdlet requires the Microsoft .NET Framework 3.5 or greater.
This version of the Microsoft .NET Framework is however not required for
PowerShell remoting.
2. Type Y to continue.
3. Type the following command to verify that the service is running
get-service winrm
4. Type the following command to view additional details about the WinRM client
configuration.
winrm get winrm/config/client
Microsoft Confidential
Page 340 of 361
Microsoft Confidential
Page 341 of 361
2. Look for the Doman Profile GPO under Administrative Templates, Network,
Network Connections and Windows Firewall.
The Windows Firewall: Define inbound Port Exceptions setting can be used to
enable an inbound firewall exception for the WS-Management listener service on
port 5985 for the TCP protocol.
3. Look for the Windows Remote Management and Windows Remote Shell GPO’s
under Administrative Templates and Windows Components.
The Allow automatic configuration of listeners setting allows automatic
configuration of the WS-Management listener port for all machines. A wildcard (*)
for each filter allows messages from many remote machines. This can alternatively
be populated with a comma-separated list or dash-separated range of IP v4 or IP v6
addresses.
The Allow Remote Shell Access setting allows remote shell access to the machine.
Note: The Windows Remote Management GPO also allows setting the
authentication protocol. The options are Kerberos, Negotiate, CredSSP and Basic.
The default authentication protocol is Kerberos for domain joined machines and
NTLM for non-domain joined machines.
All WinRM traffic is encrypted by default. Unencrypted traffic can be enabled using
the ‘Allow unencrypted traffic’ GPO setting.
Microsoft Confidential
Page 342 of 361
Scenario
To run a command on remote machines on a one-time-only basis, use Invoke-Command.
This Cmdlet can accept a list of remote computer names in its –ComputerName
parameter. The command to actually run on the remote machine is in the form of a
scriptblock and therefore, enclosed in curly braces.
Process information related to both the syddc01 and w7client machines are returned.
Note that a PSComputerName column is added to the output.
Microsoft Confidential
Page 343 of 361
This command stores a query in a variable for use in the next command.
2. Type the following command
$job = invoke-command -computername syddc01,w7client -ScriptBlock $command -
ThrottleLimit 2 -AsJob
Jobs can also be used in conjunction with PowerShell remoting. A long-running job
run against many machines can be executed in a background thread so that control is
immediately returned to the shell and the user can continue with another task. To do
this, include the -AsJob parameter in the Invoke-Command Cmdlet and save the
command to a variable reference.
3. Type the following command.
$job
To view the results of child jobs, use the childjobs property of the $job object.
5. Type the following command.
receive-job -name job2 -keep
Use the Receive-Job Cmdlet to view the information returned from each remote
machine. The keep parameter is used to keep the data available for future retrieval
using the receive-job Cmdlet.
Note: It is possible for the job number to be different. Take note of the job names
that are displayed after step 4 above.
Microsoft Confidential
Page 344 of 361
Microsoft Confidential
Page 345 of 361
Scenario
The Invoke-Command approach is useful for one-off commands. However, if you want
to run a series of commands against remote machines and store variables that you can
access later, you need to use the PowerShell remoting concept of a session, which is
persisted between commands. The New-PSSession Cmdlet enables the creation of a new
persistent PowerShell run space on a remote computer, which is not destroyed every time
a command is issued.
You can specify a single or multiple machines to create sessions with and run a command
against each session.
Microsoft Confidential
Page 346 of 361
This command uses the session that was created in step 1 and retrieves the processor
architecture for both the syddc01 and w7client machines. Note that the session is not
destroyed and can be used again.
4. Type the following command.
$session1 = get-pssession -id 1
The Get-PSSession Cmdlet allows you to get a reference to these sessions by their
identifier property.
5. Type the following command to list information related to the session identifier.
$session1
The Get-PSSession Cmdlet allows you to get a reference to these sessions by their
identifier property.
7. Type the following command to list information related to the session identifier.
$session2
8. Type the following command to run a command against a specific session identifier
as opposed to against all session identifiers that were created during step 1 in the
$mysession variable.
invoke-command -session $session1 -scriptblock {$env:computername}
9. Type the following command to return the ComputerName that relates to the other
session.
invoke-command -session $session2 -scriptblock {$env:computername}
10. In this example, you will create a variable in one command and then demonstrate
using that variable in a subsequent command.
A. Type the following command.
invoke-command -session $session2 -scriptblock {$date = get-date -
displayhint time}
Microsoft Confidential
Page 347 of 361
Microsoft Confidential
Page 348 of 361
Scenario
The last type of remote session is an interactive remote session. The Enter-PSSession
Cmdlet automatically creates a remote session object and allows you to enter commands
as if you were physically sitting in front of the PowerShell console of the remote
computer. The Exit-PSSession Cmdlet takes you out of the remote interactive session.
2. Type the following commands to confirm the computer name. Note that using this
session is just like being at the console of the syddc01 machine.
$envvar = $env:computername
$envvar
Microsoft Confidential
Page 349 of 361
2. Type the following command to enter the session using an existing session reference.
enter-pssession –session $mysession
3. Type the following commands to confirm the computer name. Note that using this
session is just like being at the console of the syddc01 machine.
$envvar = $env:computername
$envvar
Microsoft Confidential
Page 350 of 361
Scenario
A very useful advanced feature of remote sessions is the ability to create constrained
configuration environments to which remote users can connect.
The Register-PSSessionConfiguration cmdlet is run on a local machine to create a new
configuration name with a number of configuration options.
Microsoft Confidential
Page 351 of 361
5. Type Y to confirm the action and Y again to confirm restarting the WinRM service.
This command will create a new session configuration with the name.
RemoteAdmin. The script file from the previous step is specified as the
configuration source. The MaximumReceivedDataSizePerCommandMB
parameter limits the amount of data that can be sent to the machine in any single
remote command. The MaximumReceivedObjectSizeMB parameter limits the
amount of data that can be sent to the machine in any single object.
6. Type the following command again to view the configured sessions on this machine
now.
get-pssessionconfiguration | format-list -property name, permission
Note that permissions have not been configured for the new RemoteAdmin session
configuration.
7. Type the following command to configure permissions for the new RemoteAdmin
session configuration.
set-pssessionconfiguration remoteadmin –showsecuritydescriptorui
Microsoft Confidential
Page 352 of 361
Permissions have now been configured for the RemoteAdmin session configuration.
2. Type the following command to return a list of all the available commands.
invoke-command -session $s -scriptblock {get-command}
Microsoft Confidential
Page 353 of 361
Note that these still work, even though the associated Cmdlets have been disabled.
5. Type the following command to remove all sessions from the machine.
get-pssession | remove-pssession
Microsoft Confidential
Page 354 of 361
Prerequisites
The lab requires a Windows 7 client running in a domain environment.
Microsoft Confidential
Page 355 of 361
Microsoft Confidential
Page 356 of 361
Password: P@ssword
7. Type the following command to use the credentials with invoke-command
Invoke-command –computername syddc01 –credential $Credentials –scriptblock
{get-process}
Microsoft Confidential
Page 357 of 361
The above command will return the computername of the computers. Since this is a
reusable session, you can create remote variables.
4. Type the following command to create a remote variable
Invoke-command –session $mysessions –scriptblock {$lastboot = (get-eventlog –
logname system | where-object {$_.eventid –eq 6005} | select-object –first 1 –
property timegenerated).timegenerated}
7. Type the following command to read events from the WinRM eventlog.
Microsoft Confidential
Page 358 of 361
You will now see the details for the psession on w7client. Note that is currently open.
9. Type the following command to remove the session.
Get-PSSession | where {$_.computername -like "w7client"} | Remove-PSSession
10. Type the following command to view the details of the $mysessions variable.
$mysessions
You will now see the details for both sessions. Note that because you removed the
session for w7client, it is now displayed as closed with availability as none.
11. Type the following command to use the sessions.
Invoke-command -session $mysessions -scriptblock {"$env:computername :
$lastboot"}
You will now receive an error from w7client as the session is closed. The session is
still available for syddc01 and you will receive a result from that machine.
12. Type the following to separate the sessions.
$activesessions = Get-PSSession | where {$_.state –eq “Opened” –and
$_.availability –eq “Available”}
This will now run without errors as only active sessions are stored in the
$activesessions variable.
Microsoft Confidential
Page 359 of 361
You will get a false result as the share does not currently exist.
3. In the PowerShell console, type the following.
Enter-pssession syddc01
This will now enter an interactive remote console on syddc01. Note that the prompt
has changed to [syddc01]: PS C:\Users\Administrator\Documents>
This indicates that the console is now operating on syddc01.
4. In the console, type the following command to change location.
Set-location c:\shares
Microsoft Confidential
Page 360 of 361
The line above creates an instance of the class win32_share with the wmiclass type
alias.
This is required as using get-wmiobject will not expose the create method.
7. Type the following command to create a new share on the server.
$wmiclass.Create("C:\shares\software","software",0)
The command above creates the share. The first part of the create method call is the
share path, the second part is the name of the share and the third part is the type of
share.
You will now get a true result as the share now exists.
Microsoft Confidential