PowerShell breaks any line that you enter into
its individual units (tokens), and then interprets each token
in one of two ways: as a command or as an expression. The difference is
subtle: expressions support logic and flow control statements (such as
if
, foreach
, and throw
), whereas commands do not.
You will often want to control the way that Windows PowerShell interprets your statements, so Table A-1 lists the options available to you.
Table A-1. Windows PowerShell evaluation controls
To create single-line comments, begin a line with the
#
character. To create a block (or multiline) comment, surround the region with the
characters <#
and #>.
# This is a regular comment <# This is a block comment function MyTest { "This should not be considered a function" } $myVariable = 10; Block comment ends #> # This is regular script again
Windows PowerShell provides several ways to define and access variables, as summarized in Table A-2.
Table A-2. Windows PowerShell variable syntaxes
Unlike some languages, PowerShell rounds
(rather than truncates) numbers when it converts them to the [int]
data type:
PS > (3/2) 1.5 PS > [int] (3/2) 2
To have PowerShell truncate a number, see Chapter 6.
Boolean (true or false) variables are most commonly
initialized to their literal values of $true
and $false
. When PowerShell evaluates variables as part of a Boolean
expression (for example, an if
statement), though, it maps them to a suitable Boolean representation, as
listed in Table A-3.
Windows PowerShell offers several facilities for working with plain-text data.
To define a literal string (one in which no variable or escape expansion occurs), enclose it in single quotes:
$myString = 'hello `t $ENV:SystemRoot'
$myString
gets the actual value of hello `t
$ENV:SystemRoot
.
To define an expanding string (one in which variable and escape expansion occur), enclose it in double quotes:
$myString = "hello `t $ENV:SystemRoot"
$myString
gets a value similar to hello
C:WINDOWS
.
To include a single quote in a single-quoted string or a double quote in a double-quoted string, include two of the quote characters in a row:
PS > "Hello ""There""!" Hello "There"! PS > 'Hello ''There''!' Hello 'There'!
To include a complex expression inside an expanding string, use a subexpression. For example:
$prompt = "$(get-location) >"
$prompt
gets a value similar to c: emp
>
.
Accessing the properties of an object requires a subexpression:
$output = "Current script name is: $($myInvocation.MyCommand.Path)"
$output
gets a value similar to Current script name
is c:Test-Script.ps1
.
To define a here string (one that may span
multiple lines), place the two characters @"
at the beginning and the two
characters "@
on their own line at the end.
$myHereString = @" This text may span multiple lines, and may contain "quotes." "@
Here strings may be of either the literal (single-quoted) or expanding (double-quoted) variety.
Windows PowerShell supports escape sequences inside strings, as listed in Table A-4.
Table A-4. Windows PowerShell escape sequences
PowerShell offers several options for interacting with numbers and numeric data.
To define a variable that holds numeric data, simply assign it as you would other variables. PowerShell automatically stores your data in a format that is sufficient to accurately hold it.
$myInt = 10
$myInt
gets
the value of 10
, as a (32-bit)
integer.
$myDouble = 3.14
$myDouble
gets the value of 3.14
, as a (53-bit,
9 bits of precision) double.
To explicitly assign a number as a long (64-bit) integer or decimal (96-bit, 96 bits of precision), use the long and decimal suffixes:
$myLong = 2147483648L
$myLong
gets the value of 2147483648
, as a
long integer.
$myDecimal = 0.999D
$myDecimal
gets the value of 0.999
.
PowerShell also supports scientific notation,
where e
<number> represents multiplying the
original number by the <number> power of 10:
$myPi = 3141592653e-9
$myPi
gets
the value of 3.141592653
.
The data types in PowerShell (integer, long integer, double, and decimal) are built on the .NET data types of the same names.
Since computer administrators rarely get the chance to
work with numbers in even powers of 10, PowerShell offers the numeric
constants of pb
, tb
, gb
, mb
, and
kb
to represent petabytes (1125899906842624),
terabytes (1099511627776), gigabytes (1073741824), megabytes (1048576),
and kilobytes (1024), respectively:
PS > $downloadTime = (1gb + 250mb) / 120kb PS > $downloadTime 10871.4666666667
To directly enter a hexadecimal number, use the
hexadecimal prefix 0x
:
$myErrorCode = 0xFE4A
$myErrorCode
gets the integer value 65098
.
The PowerShell scripting language does not natively support other number bases, but its support for interaction with the .NET Framework enables conversion to and from binary, octal, decimal, and hexadecimal:
$myBinary = [Convert]::ToInt32("101101010101", 2)
$myBinary
gets the
integer value of 2901
.
$myOctal = [Convert]::ToInt32("1234567", 8)
$myOctal
gets the
integer value of 342391
.
$myHexString = [Convert]::ToString(65098, 16)
$myHexString
gets the string value of fe4a
.
$myBinaryString = [Convert]::ToString(12345, 2)
$myBinaryString
gets the string value of
11000000111001
.
See Working with the .NET Framework to learn more about using PowerShell to interact with the .NET Framework.
PowerShell arrays hold lists of data. The @()
(array cast)
syntax tells PowerShell to treat the contents between the parentheses as
an array. To create an empty array, type:
$myArray = @()
To define a nonempty array, use a comma to separate its elements:
$mySimpleArray = 1,"Two",3.14
Arrays may optionally be only a single element long:
$myList = ,"Hello"
Or, alternatively (using the array cast syntax):
$myList = @("Hello")
Elements of an array do not need to be all of
the same data type, unless you declare it as a strongly typed array. In the following example, the outer
square brackets define a strongly typed variable (as mentioned in Variables), and int[]
represents an
array of integers:
[int[]] $myArray = 1,2,3.14
In this mode, PowerShell generates an error if
it cannot convert any of the elements in your list to the required data
type. In this case, it rounds 3.14
to the integer
value of 3:
PS > $myArray[2] 3
To ensure that PowerShell treats collections
of uncertain length (such as history lists or directory listings) as a
list, use the list evaluation syntax @(…)
described
in Commands and Expressions.
Arrays can also be multidimensional jagged arrays (arrays within arrays):
$multiDimensional = @( (1,2,3,4), (5,6,7,8) )
$multiDimensional[0][1]
returns 2, coming from
row 0, column 1.
$multiDimensional[1][3]
returns 8, coming from
row 1, column 3.
To define a multidimensional array that is not
jagged, create a multidimensional instance of the .NET type. For
integers, that would be an array of
System.Int32
:
$multidimensional = New-Object "Int32[,]" 2,4 $multidimensional[0,1] = 2 $multidimensional[1,3] = 8
To access a specific element in an array, use the
[]
operator. PowerShell numbers your array elements
starting at zero. Using $myArray =
1,2,3,4,5,6
as an example:
$myArray[0]
returns 1, the first element in the array.
$myArray[2]
returns 3, the third element in the array.
$myArray[-1]
returns 6, the last element of the array.
$myArray[-2]
returns 5, the second-to-last element of the array.
You can also access ranges of elements in your array:
PS > $myArray[0..2] 1 2 3
returns elements 0 through 2, inclusive.
PS > $myArray[-1..2] 6 1 2 3
returns the final element, wraps around, and returns elements 0 through 2, inclusive. PowerShell wraps around because the first number in the range is positive, and the second number in the range is negative.
PS > $myArray[-1..-3] 6 5 4
returns the last element of the array through to the third-to-last element in array, in descending order. PowerShell does not wrap around (and therefore scans backward in this case) because both numbers in the range share the same sign.
You can combine several of the statements in the previous section at once to extract more complex ranges from an array. Use the + sign to separate array ranges from explicit indexes:
$myArray[0,2,4]
returns the elements at indices 0, 2, and 4.
$myArray[0,2+4..5]
returns the elements at indices 0, 2, and 4 through 5, inclusive.
$myArray[,0+2..3+0,0]
returns the elements at indices 0, 2 through 3 inclusive, 0, and 0 again.
PowerShell hashtables (also called associative arrays) let you associate keys with values. To define a hashtable, use the syntax:
$myHashtable = @{}
You can initialize a hashtable with its key/value pairs when you create it. PowerShell assumes that the keys are strings, but the values may be any data type.
$myHashtable = @{ Key1 = "Value1"; "Key 2" = 1,2,3; 3.14 = "Pi" }
PowerShell supports XML as a native data type. To create an
XML variable, cast a string to the [xml]
type:
$myXml = [xml] @" <AddressBook> <Person contactType="Personal"> <Name>Lee</Name> <Phone type="home">555-1212</Phone> <Phone type="work">555-1213</Phone> </Person> <Person contactType="Business"> <Name>Ariel</Name> <Phone>555-1234</Phone> </Person> </AddressBook> "@
PowerShell exposes all child nodes and attributes as properties. When it does this, PowerShell automatically groups children that share the same node type:
$myXml.AddressBook
returns an object that contains a Person
property.
$myXml.AddressBook.Person
returns a list of Person
nodes. Each person node exposes contactType
, Name
, and Phone
as properties.
$myXml.AddressBook.Person[0]
returns the first Person
node.
$myXml.AddressBook.Person[0].ContactType
returns Personal
as the contact type of the first
Person
node.
Once you have defined your data, the next step is to work with it.
The arithmetic operators let you perform mathematical operations on your data, as shown in Table A-5.
The System.Math
class in the .NET Framework
offers many powerful operations in addition to the native operators
supported by PowerShell:
PS > [Math]::Pow([Math]::E, [Math]::Pi) 23.1406926327793
See Working with the .NET Framework to learn more about using PowerShell to interact with the .NET Framework.
Table A-5. Windows PowerShell arithmetic operators
The logical operators let you compare Boolean values, as shown in Table A-6.
Table A-6. Windows PowerShell logical operators
The binary operators, listed in Table A-7, let you apply the
Boolean logical operators bit by bit to the operator’s arguments. When
comparing bits, a 1 represents $true
,
whereas a 0 represents $false
.
Table A-7. Windows PowerShell binary operators
PowerShell supports several other simple operators, as listed in Table A-8.
Table A-8. Other Windows PowerShell operators
Returns a new string, where the text in
By default, PowerShell performs a
case-insensitive comparison. The If the regular expression pattern contains named captures or capture groups, the replacement string may reference those as well. PS > "Hello World" -replace "(.*) (.*)",'$2 $1' World Hello If
For more information on the details of regular expressions, see Appendix B. | |
Returns a string where the format items in the format string have been replaced with the text equivalent of the values in the value array. PS > "{0:n0}" -f 1000000000 1,000,000,000 The format string for
the format operator is exactly the format string supported by
the .NET For more details about the syntax of the format string, see Appendix D. | |
Returns PS > 3/2 -as [int] 2 PS > $result = "Hello" -as [int] PS > $result -eq $null True | |
-split Breaks the given
input string into an array, using whitespace
( PS > -split " Hello World " Hello World "Input String" -split " Breaks the given input string into an array, using the given
PS > "1a2B3" -split "[a-z]+",0,"IgnoreCase" 1 2 3 | |
-join Combines the supplied items into a single string, using no separator. For example: PS > -join ("a","b") ab
Combines the supplied items into a single
string, using PS > ("a","b") -join ", " a, b |
The PowerShell comparison operators, listed in Table A-9, let you compare
expressions against each other. By default, PowerShell’s comparison
operators are case-insensitive. For all operators where case sensitivity
applies, the -i
prefix makes this case
insensitivity explicit, whereas the -c
prefix performs a case-sensitive comparison.
Table A-9. Windows PowerShell comparison operators
For all primitive types, returns When used with arrays, returns all elements in
When used with any other type, PowerShell uses
that type’s | |
The negated equality operator:
For all primitive types, returns
When used with arrays,
returns all elements in When used with any other type, PowerShell
returns the negation of that type’s | |
The greater-than-or-equal operator:
For all primitive types, returns When used with arrays, returns all elements in
When used with any other type, PowerShell
returns the result of that object’s | |
$leftValue -gt $rightValue For all primitive types, returns When used with arrays, returns all elements in
When used with any other type, PowerShell
returns the result of that object’s | |
For all primitive types, returns When used with arrays, returns all elements in
When used with any other type, PowerShell
returns the result of that object’s | |
The less-than-or-equal operator:
For all primitive types, returns When used with arrays, returns all elements in
When used with any other type, PowerShell
returns the result of that object’s | |
Evaluates the pattern against the target,
returning When used
with arrays, returns all elements in
The
PS > "Test" -like "[A-Z]e?[tr]" True | |
Evaluates the regular expression against the
target, returning When used with arrays, returns all elements in
The
PS > "Hello World" -match "(.*) (.*)" True PS > $matches[1] Hello For more information on the details of regular expressions, see Appendix B. | |
Returns
The | |
Returns | |
The negated contains operator: Returns
| |
Returns | |
Conditional statements in PowerShell let you change the flow of execution in your script.
if(condition)
{ statement block } elseif(condition)
{ statement block } else { statement block }
If condition
evaluates to $true
, PowerShell
executes the statement block you provide. Then, it resumes execution at
the end of the if/elseif/else
statement list. PowerShell requires the enclosing braces around the
statement block, even if the statement block contains only one
statement.
See Simple Operators and Comparison Operators for a discussion on how PowerShell evaluates expressions as conditions.
If condition
evaluates to $false
, PowerShell
evaluates any following (optional) elseif
conditions
until one matches. If one matches, PowerShell executes the statement
block associated with that condition, and then resumes execution at the
end of the if/elseif/else
statement
list.
$textToMatch = Read-Host "Enter some text" $matchType = Read-Host "Apply Simple or Regex matching?" $pattern = Read-Host "Match pattern" if($matchType -eq "Simple") { $textToMatch -like $pattern } elseif($matchType -eq "Regex") { $textToMatch -match $pattern } else { Write-Host "Match type must be Simple or Regex" }
If none of the conditions evaluate to $true
, PowerShell executes the statement block
associated with the (optional) else
clause, and then resumes execution at the end of the if/elseif/else
statement list.
switchoptions expression
{comparison value
{statement block
} -or- {comparison expression
} {statement block
} (...) default {statement block
} }
switchoptions
-filefilename
{comparison value
{statement block
} -or {comparison expression
} {statement block
} (...) default {statement block
} }
When PowerShell evaluates a switch
statement, it evaluates
expression
against the statements in the
switch body. If expression
is a list of
values, PowerShell evaluates each item against the statements in the
switch body. If you specify the -file
option, PowerShell treats the lines in the file as though they were a
list of items in expression
.
The comparison
value
statements let you match the current input item
against the pattern specified by comparison
value
. By default, PowerShell treats this as a
case-insensitive exact match, but
the options you provide to the switch
statement can change this, as shown in Table A-10.
Table A-10. Options supported by PowerShell switch statements
| With this option active,
PowerShell executes the associated statement block only if the
current input item exactly matches the value specified by
|
| With this option active, PowerShell
executes the associated statement block only if the current
input item exactly matches the value specified by
|
| With this option active, PowerShell
executes the associated statement block only if the current
input item matches the regular expression specified by
|
| With this option active, PowerShell
executes the associated statement block only if the current
input item matches the wildcard specified by
The wildcard match supports the following simple wildcard characters:
|
The {
comparison expression
}
statements let you process the current input item, which is stored in
the $_
variable, in an arbitrary
script block. When it processes a {
comparison expression
}
statement, PowerShell executes the associated statement block only if
{
comparison expression
}
evaluates to $true
.
PowerShell executes the statement block
associated with the (optional) default
statement if no other statements in
the switch
body match.
When processing a switch
statement, PowerShell tries to match
the current input object against each statement in the switch
body, falling through to the next
statement even after one or more have already matched. To have
PowerShell discontinue the current comparison (but retry the switch
statement with the next input object), include a
continue
statement as the last statement in the
statement block. To have PowerShell exit a switch
statement completely after it processes
a match, include a break
statement as
the last statement in the statement block.
$myPhones = "(555) 555-1212","555-1234" switch -regex ($myPhones) { { $_.Length -le 8 } { "Area code was not specified"; break } { $_.Length -gt 8 } { "Area code was specified" } "((555)).*" { "In the $($matches[1]) area code" } }
Area code was specified In the 555 area code Area code was not specified
See Looping Statements
for more information about the break
statement.
By default, PowerShell treats this as a
case-insensitive exact match, but the options you provide to the
switch
statement can change
this.
Looping statements in PowerShell let you execute groups of statements multiple times.
:loop_label
for (initialization
;condition
;increment
) {statement block
}
When PowerShell executes a
for
statement, it first executes the expression given
by initialization
. It next
evaluates condition
. If
condition
evaluates to $true
, PowerShell executes the given statement
block. It then executes the expression given by increment
. PowerShell continues to
execute the statement block and increment
statement as long as condition
evaluates to
$true
.
for($counter = 0; $counter -lt 10; $counter++) { Write-Host "Processing item $counter" }
The break
and continue
statements (discussed
later in this appendix) can specify the
loop_label
of any enclosing looping statement
as their target.
:loop_label
foreach (variable in expression
) {statement block
}
When PowerShell executes a foreach
statement, it executes the pipeline
given by expression
—for example,
Get-Process | Where-Object {$_.Handles -gt 500}
or
1..10
. For each item produced by the expression, it
assigns that item to the variable specified by
variable
and then executes the given
statement block. For example:
$handleSum = 0; foreach($process in Get-Process | Where-Object { $_.Handles -gt 500 }) { $handleSum += $process.Handles } $handleSum
The break
and continue
statements (discussed
later in this appendix) can specify the
loop_label
of any enclosing looping statement
as their target. In addition to the foreach
statement, PowerShell also offers
the Foreach-Object
cmdlet with similar capabilities.
For more information, see Repeat Operations with Loops.
:loop_label
while(condition
) {statement block
}
When PowerShell executes a while
statement, it first evaluates the
expression given by condition
. If this
expression evaluates to $true
,
PowerShell executes the given statement block. PowerShell continues to
execute the statement block as long as condition
evaluates to $true
. For example:
$command = ""; while($command -notmatch "quit") { $command = Read-Host "Enter your command" }
The break
and continue
statements (discussed
later in this appendix) can specify the
loop_label
of any enclosing looping statement
as their target.
:loop_label
do {statement block
} while(condition
)
:loop_label
do {statement block
} until(condition
)
When PowerShell executes a do …
while
or do … until
statement, it first executes the given statement block. In a do … while
statement, PowerShell continues to
execute the statement block as long as
condition
evaluates to $true
. In a do …
until
statement, PowerShell continues to execute the statement
as long as condition
evaluates to $false
. For example:
$validResponses = "Yes","No" $response = "" do { $response = read-host "Yes or No?" } while($validResponses -notcontains $response) "Got it." $response = "" do { $response = read-host "Yes or No?" } until($validResponses -contains $response) "Got it."
The break
and continue
statements (discussed
later in this appendix) can specify the
loop_label
of any enclosing looping statement
as their target.
PowerShell supports two statements to help you control
flow within loops: break
and continue
.
The break
statement
halts execution of the current loop. PowerShell then resumes execution
at the end of the current looping statement, as though the looping
statement had completed naturally. For example:
for($counter = 0; $counter -lt 5; $counter++) { for($counter2 = 0; $counter2 -lt 5; $counter2++) { if($counter2 -eq 2) { break } Write-Host "Processing item $counter,$counter2" } }
produces the output:
Processing item 0,0 Processing item 0,1 Processing item 1,0 Processing item 1,1 Processing item 2,0 Processing item 2,1 Processing item 3,0 Processing item 3,1 Processing item 4,0 Processing item 4,1
If you specify a label with the break
statement—for example, break outer_
loop
—PowerShell halts the execution of that
loop instead. For example:
:outer_loop for($counter = 0; $counter -lt 5; $counter++) { for($counter2 = 0; $counter2 -lt 5; $counter2++) { if($counter2 -eq 2) { break outer_loop } Write-Host "Processing item $counter,$counter2" } }
Processing item 0,0 Processing item 0,1
The continue
statement skips execution of the rest of the current statement block.
PowerShell then continues with the next iteration of the current
looping statement, as though the statement block had completed
naturally. For example:
for($counter = 0; $counter -lt 5; $counter++) { for($counter2 = 0; $counter2 -lt 5; $counter2++) { if($counter2 -eq 2) { continue } Write-Host "Processing item $counter,$counter2" } }
Processing item 0,0 Processing item 0,1 Processing item 0,3 Processing item 0,4 Processing item 1,0 Processing item 1,1 Processing item 1,3 Processing item 1,4 Processing item 2,0 Processing item 2,1 Processing item 2,3 Processing item 2,4 Processing item 3,0 Processing item 3,1 Processing item 3,3 Processing item 3,4 Processing item 4,0 Processing item 4,1 Processing item 4,3 Processing item 4,4
If you specify a label with the continue
statement—for example, continue outer_
loop
—PowerShell continues with the next
iteration of that loop instead.
:outer_loop for($counter = 0; $counter -lt 5; $counter++) { for($counter2 = 0; $counter2 -lt 5; $counter2++) { if($counter2 -eq 2) { continue outer_loop } Write-Host "Processing item $counter,$counter2" } }
Processing item 0,0 Processing item 0,1 Processing item 1,0 Processing item 1,1 Processing item 2,0 Processing item 2,1 Processing item 3,0 Processing item 3,1 Processing item 4,0 Processing item 4,1
One feature that gives PowerShell its incredible reach into both system administration and application development is its capability to leverage Microsoft’s enormous and broad .NET Framework.
Work with the .NET Framework in PowerShell comes mainly by way of one of two tasks: calling methods or accessing properties.
To call a static method on a class, type:
[ClassName
]::MethodName
(parameter list
)
PS > [System.Diagnostics.Process]::GetProcessById(0)
gets the process with the ID of 0 and displays the following output:
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 0 0 0 16 0 0 Idle
To call a method on an instance of an object, type:
$objectReference
.MethodName
(parameter list
)
PS > $process = [System.Diagnostics.Process]::GetProcessById(0) PS > $process.Refresh()
This stores the process with ID of 0 into the
$process
variable. It then calls the
Refresh()
instance method on that
specific process.
To access a static property on a class, type:
[ClassName
]::PropertyName
[ClassName
]::PropertyName
=value
For example, the [System.DateTime]
class provides a Now
static property
that returns the current time:
PS > [System.DateTime]::Now Sunday, July 16, 2006 2:07:20 PM
Although this is rare, some types let you set the value of some static properties.
To access an instance property on an object, type:
$objectReference
.PropertyName
$objectReference
.PropertyName
=value
PS > $today = [System.DateTime]::Now PS > $today.DayOfWeek Sunday
This stores the current date in the $today
variable. It then calls the DayOfWeek
instance property on that specific
date.
The two primary avenues for learning about classes and
types are the Get-Member
cmdlet and
the documentation for the .NET Framework.
To learn what methods and properties a given
type supports, pass it through the Get-Member
cmdlet, as shown in Table A-11.
Table A-11. Working with the Get-Member cmdlet
Another source of information about the classes in the .NET Framework is the documentation itself, available through the search facilities at http://msdn.microsoft.com.
Typical documentation for a class first starts with a general overview, and then provides a hyperlink to the members of the class—the list of methods and properties it supports.
To get to the documentation for the members quickly, search for them more explicitly by adding the term “members” to your MSDN search term:
classname
members
The documentation for the members of a class lists their constructors, methods, properties, and more. It uses an S icon to represent the static methods and properties. Click the member name for more information about that member, including the type of object that the member produces.
When you specify a type name, PowerShell lets you use a short form for some of the most common types, as listed in Table A-12.
$objectReference
= New-ObjectTypeName
parameters
Although static methods and properties of a
class generate objects, you will often want to create them explicitly
yourself. PowerShell’s New-Object
cmdlet lets
you create an instance of the type you specify. The parameter list must
match the list of parameters accepted by one of the type’s constructors,
as documented on MSDN.
$webClient = New-Object Net.WebClient $webClient.DownloadString("http://search.msn.com")
If the type represents a generic type, enclose its type parameters in square brackets:
PS > $hashtable = New-Object "System.Collections.Generic.Dictionary[String,Bool]" PS > $hashtable["Test"] = $true
Most common types are available by default. However, many types are available only after you load the library (called the assembly) that defines them. The MSDN documentation for a class includes the assembly that defines it.
To load an assembly, use the
-AssemblyName
parameter of the Add-Type
cmdlet:
PS > Add-Type -AssemblyName System.Web PS > [Web.HttpUtility]::UrlEncode("http://www.bing.com") http%3a%2f%2fwww.bing.com
PowerShell lets you access methods and
properties on COM objects the same way you would interact with objects
from the .NET Framework. To interact with a COM object, use its ProgId
with the -ComObject
parameter (often shortened to
-Com
) on New-Object
:
PS > $shell = New-Object -Com Shell.Application PS > $shell.Windows() | Select-Object LocationName,LocationUrl
For more information about the COM objects most useful to system administrators, see Appendix H.
PowerShell supports two ways to add your own methods and
properties to any type: the Add-Member
cmdlet and a custom types extension
file.
The Add-Member
cmdlet
lets you dynamically add methods, properties, and more to an object.
It supports the extensions shown in Table A-13.
Table A-13. Selected member types supported by the Add-Member cmdlet
While the Add-Member
cmdlet lets you customize individual objects, PowerShell also supports
configuration files that let you customize all objects of a given
type. For example, you might want to add a Reverse()
method to
all strings or a HelpUrl
property
(based on the MSDN Url Aliases) to all types.
PowerShell adds several type extensions to
the file types.ps1xml, in the PowerShell
installation directory. This file is useful as a source of examples,
but you should not modify it directly. Instead, create a new one and
use the Update-TypeData
cmdlet to load your customizations. The following command loads
Types.custom.ps1xml from the same
directory as your profile:
$typesFile = Join-Path (Split-Path $profile) "Types.Custom.Ps1Xml" Update-TypeData -PrependPath $typesFile
For more information about custom type extensions files, see Add Custom Methods and Properties to Types.
When you want to start packaging and reusing your commands, the best place to put them is in scripts, functions, and script blocks. A script is a text file that contains a sequence of PowerShell commands. A function is also a sequence of PowerShell commands but is usually placed within a script to break it into smaller, more easily understood segments. A script block is a function with no name. All three support the same functionality, except for how you define them.
To write a script, write your PowerShell commands in a text editor and save the file with a .ps1 extension.
Functions let you package blocks of closely related commands into a single unit that you can access by name.
function SCOPE:name(parameters)
{statement block
}
filter SCOPE:name(parameters)
{statement block
}
Valid scope names are global
(to create a function available to
the entire shell), script
(to
create a function available only to the current script), local
(to create a function available only
to the current scope and subscopes), and private
(to create a function available only
to the current scope). The default scope is the local
scope, which follows the same rules as
those of default variable scopes.
The content of a function’s statement block follows the same
rules as the content of a script. Functions support the $args
array, formal parameters, the $input
enumerator, cmdlet keywords, pipeline
output, and equivalent return semantics.
A common mistake is to call a function as you would call a method:
$result = GetMyResults($item1, $item2)
PowerShell treats functions as it treats scripts and other commands, so this should instead be:
$result = GetMyResults $item1 $item2
The first command passes an array that
contains the items $item1
and
$item2
to the GetMyResults
function.
A filter is simply a function where the statements are
treated as though they are contained within a process
statement block. For more
information about process
statement blocks, see
Cmdlet keywords in commands.
Commands in your script can access only functions that have already been defined. This can often make large scripts difficult to understand when the beginning of the script is composed entirely of helper functions. Structuring a script in the following manner often makes it more clear:
function Main { (...) HelperFunction (...) } function HelperFunction { (...) } . Main
$objectReference =
{
statement block
}
PowerShell supports script blocks, which act
exactly like unnamed functions and scripts. Like both scripts and
functions, the content of a script block’s statement block follows the
same rules as the content of a function or script. Script blocks
support the $args
array, formal
parameters, the $input
enumerator,
cmdlet keywords, pipeline output, and equivalent return
semantics.
As with both scripts and functions, you can
either invoke or dot-source a script block. Since a script block does
not have a name, you either invoke it directly
(&
{ "Hello"
}) or invoke the variable
(&
$objectReference
) that contains it.
There are two ways to execute a command (script, function, or script block): by invoking it or by dot-sourcing it.
Invoking a command runs the commands inside it. Unless
explicitly defined with the GLOBAL
scope keyword, variables and functions defined in the script do not
persist once the script exits.
By default, a security feature in
PowerShell called the Execution Policy prevents scripts from
running. When you want to enable scripting in PowerShell, you must
change this setting. To understand the different execution policies available to you, type Get-Help about_signing
. After selecting an
execution policy, use the Set-ExecutionPolicy
cmdlet to configure it:
Set-ExecutionPolicy RemoteSigned
If the command name has no spaces, simply type its name:
c: empInvoke-Commands.ps1parameter1 parameter2 ...
Invoke-MyFunctionparameter1 parameter2 ...
You can use either a fully qualified path or a path relative to the current location. If the script is in the current directory, you must explicitly say so:
.Invoke-Commands.ps1 parameter1 parameter2 ...
If the command’s name has a space (or the
command has no name, in the case of a script block), you invoke the
command by using the invoke/call operator (&
)
with the command name as the parameter.
& "C:Script DirectoryInvoke-Commands.ps1" parameter1 parameter2 ...
Script blocks have no name, so you place the variable holding them after the invocation operator:
$scriptBlock = { "Hello World" }
& $scriptBlock parameter1 parameter2 ...
If you want to invoke the command within the context of a module, provide a reference to that module as part of the invocation:
$module = Get-Module PowerShellCookbook &$module
Invoke-MyFunctionparameter1 parameter2 ...
&$module
$scriptBlockparameter1 parameter2 ...
Dot-sourcing a command runs the commands inside it. Unlike simply invoking a command, variables and functions defined in the script do persist after the script exits.
You invoke a script by using the dot
operator (.
) and providing the command name as the
parameter:
. "C:Script DirectoryInvoke-Commands.ps1"Parameters
. Invoke-MyFunctionparameters
. $scriptBlockparameters
When dot-sourcing a script, you can use either a fully qualified path or a path relative to the current location. If the script is in the current directory, you must explicitly say so:
. .Invoke-Commands.ps1 Parameters
If you want to dot-source the command within the context of a module, provide a reference to that module as part of the invocation:
$module = Get-Module PowerShellCookbook .$module
Invoke-MyFunctionparameters
.$module
$scriptBlockparameters
PowerShell offers several options for processing input to a command.
To access the command-line arguments by position, use
the argument array that PowerShell places in the $args
special variable:
$firstArgument = $args[0] $secondArgument = $args[1] $argumentCount = $args.Count
To define a command with simple parameter support:
param([TypeName] $VariableName
=Default
, ... )
To define one with support for advanced functionality:
[CmdletBinding(cmdlet behavior customizations
)] param( [Parameter(Mandatory = $true, Position = 1, ...
)] [Alias("MyParameterAlias
"] [...][TypeName] $VariableName
=Default
, ... )
Formal parameters let you benefit from some of the many benefits of PowerShell’s consistent command-line parsing engine.
PowerShell exposes your parameter names (for
example, $VariableName
) the same
way that it exposes parameters in cmdlets. Users need to type only
enough of your parameter name to disambiguate it from the rest of the
parameters.
If you define a command with simple parameter support, PowerShell attempts to assign the input to your parameters by their position if the user does not type parameter names.
When you add the [CmdletBinding()]
attribute,
[Parameter()]
attribute, or any of the validation
attributes, PowerShell adds support for advanced parameter
validation.
The elements of the [CmdletBinding()]
attribute describe how your script or function interacts with the
system.
SupportsShouldProcess = $true
If $true
, enables
the -WhatIf
and -Confirm
parameters, which tells the user that your command modifies the
system and can be run in one of these experimental modes. When
specified, you must also call the $psCmdlet.ShouldProcess()
method before modifying system state. When not specified, the
default is $false
.
DefaultParameterSetName =
name
Defines the default parameter set name of this command. This is used to resolve ambiguities when parameters declare multiple sets of parameters and the user input doesn’t supply enough information to pick between available parameter sets. When not specified, the command has no default parameter set name.
ConfirmImpact =
"High
"Defines this command as one that
should have its confirmation messages (generated by the
$psCmdlet.ShouldProcess()
method) shown by
default. More specifically, PowerShell defines three
confirmation impacts: Low
,
Medium
, and High
. PowerShell generates the cmdlet’s
confirmation messages automatically whenever the cmdlet’s impact
level is greater than the preference variable. When not
specified, the command’s impact is
Medium
.
The elements of the [Parameter()]
attribute mainly define how your parameter behaves in relation to
other parameters. All elements are optional.
Mandatory = $true
Defines the parameter as mandatory. If the user doesn’t supply a value to this parameter, PowerShell automatically prompts him for it. When not specified, the parameter is optional.
Position =
position
Defines the position of this
parameter. This applies when the user provides parameter values
without specifying the parameter they apply to (e.g.,
Argument2
in
Invoke-MyFunction -
). PowerShell
supplies these values to
parameters that have defined a Param1
Argument1
Argument2
Position
, from
lowest to highest. When not specified, the name of this
parameter must be supplied by the user.
ParameterSetName =
name
Defines this parameter as a member of
a set of other related parameters. Parameter behavior for this
parameter is then specific to this related set of parameters,
and the parameter exists only in the parameter sets that it is
defined in. This feature is used, for example, when the user may
supply only a Name or ID. To include a
parameter in two or more specific parameter sets, use two or
more [Parameter()]
attributes. When not specified, this parameter is a member of
all parameter sets.
ValueFromPipeline = $true
Declares this parameter as one that
directly accepts pipeline input. If the user pipes data into
your script or function, PowerShell assigns this input to your
parameter in your command’s process {}
block.
When not specified, this parameter does not accept pipeline
input directly.
ValueFromPipelineByPropertyName =
$true
Declares this parameter as one that
accepts pipeline input if a property of an incoming object
matches its name. If this is true, PowerShell assigns the value
of that property to your parameter in your command’s
process {}
block. When not specified, this
parameter does not accept pipeline input by property
name.
ValueFromRemainingArguments =
$true
Declares this parameter as one that accepts all remaining input that has not otherwise been assigned to positional or named parameters. Only one parameter can have this element. If no parameter declares support for this capability, PowerShell generates an error for arguments that cannot be assigned.
In addition to the [Parameter()]
attribute, PowerShell lets you apply other attributes that add
additional behavior or validation constraints to your parameters. All
validation attributes are optional.
[Alias("
name
")]
Defines an alternate name for this parameter. This is especially helpful for long parameter names that are descriptive but have a more common colloquial term. When not specified, the parameter can be referred to only by the name you originally declared.
[AllowNull()]
Allows this parameter to receive
$null
as its value. This is required only for
mandatory parameters. When not specified, mandatory parameters
cannot receive $null
as their value, although
optional parameters can.
[AllowEmptyString()]
Allows this string parameter to receive an empty string as its value. This is required only for mandatory parameters. When not specified, mandatory string parameters cannot receive an empty string as their value, although optional string parameters can. You can apply this to parameters that are not strings, but it has no impact.
[AllowEmptyCollection()]
Allows this collection parameter to receive an empty collection as its value. This is required only for mandatory parameters. When not specified, mandatory collection parameters cannot receive an empty collection as their value, although optional collection parameters can. You can apply this to parameters that are not collections, but it has no impact.
[ValidateCount(
lower
limit
, upper
limit
)]
Restricts the number of elements that can be in a collection supplied to this parameter. When not specified, mandatory parameters have a lower limit of one element. Optional parameters have no restrictions. You can apply this to parameters that are not collections, but it has no impact.
[ValidateLength(
lower
limit
, upper
limit
)]
Restricts the length of strings that this parameter can accept. When not specified, mandatory parameters have a lower limit of one character. Optional parameters have no restrictions. You can apply this to parameters that are not strings, but it has no impact.
[ValidatePattern("
regular
expression
")]
Enforces a pattern that input to this string parameter must match. When not specified, string inputs have no pattern requirements. You can apply this to parameters that are not strings, but it has no impact.
[ValidateRange(
lower
limit
, upper
limit
)]
Restricts the upper and lower limit of numerical arguments that this parameter can accept. When not specified, parameters have no range limit. You can apply this to parameters that are not numbers, but it has no impact.
[ValidateScript( {
script
block
} )]
Ensures that input supplied to this
parameter satisfies the condition that you supply in the script
block. PowerShell assigns the proposed input to the
$_
variable, and then invokes your script
block. If the script block returns $true
(or
anything that can be converted to $true
, such
as nonempty strings), PowerShell considers the validation to
have been successful.
[ValidateSet("
First
Option
", "
Second
Option
",
...,
"
Last
Option
")]
Ensures that input supplied to this
parameter is equal to one of the options in the set. PowerShell
uses its standard meaning of equality during this comparison:
the same rules used by the -eq
operator. If
your validation requires nonstandard rules (such as
case-sensitive comparison of strings), you can instead write the
validation in the body of the script or function.
[ValidateNotNull()]
Ensures that input supplied to this
parameter is not null. This is the default behavior of mandatory
parameters, so this is useful only for optional parameters. When
applied to string parameters, a $null
parameter value gets instead converted to an empty
string.
[ValidateNotNullOrEmpty()]
Ensures that input supplied to this
parameter is not null or empty. This is the default behavior of
mandatory parameters, so this is useful only for optional
parameters. When applied to string parameters, the input must be
a string with a length greater than one. When applied to
collection parameters, the collection must have at least one
element. When applied to other types of parameters, this
attribute is equivalent to the
[ValidateNotNull()]
attribute.
To access the data being passed to your command via the
pipeline, use the input enumerator that PowerShell places in the $input
special variable:
foreach($element in $input) { "Input was: $element" }
The $input
variable is a .NET enumerator over
the pipeline input. Enumerators support streaming scenarios very
efficiently but do not let you access arbitrary elements as you would
with an array. If you want to process their elements again, you must
call the Reset()
method on the
$input
enumerator once you reach
the end.
If you need to access the pipeline input in an unstructured way, use the following command to convert the input enumerator to an array:
$inputArray = @($input)
When pipeline input is a core scenario of your command,
you can include statement blocks labeled begin
, process
, and
end
:
param(...) begin { ... } process { ... } end { ... }
PowerShell executes the begin
statement when it loads your command,
the process
statement for each item
passed down the pipeline, and the end
statement after all pipeline input has
been processed. In the process
statement block, the $_
variable
represents the current pipeline object.
When you write a command that includes these keywords, all the commands in your script must be contained within the statement blocks.
PowerShell provides three primary ways to retrieve output from a command.
any command
The return value/output of a script is any data that it generates but does not capture. If a command contains the commands:
"Text Output" 5*5
then assigning the output of that command to
a variable creates an array with the two values Text Output
and 25
.
exit errorlevel
The exit
statement
returns an error code from the current command or instance of
PowerShell. If called anywhere in a script (inline, in a function, or
in a script block), it exits the script. If called outside of a script
(for example, a function), it exits PowerShell. The exit
statement sets the $LastExitCode
automatic variable to
errorLevel
. In turn, that sets the
$?
automatic variable to $false
if
errorLevel
is not zero.
PowerShell automatically generates help content out of specially tagged comments in your command:
<# .SYNOPSIS Runs a ... .EXAMPLE PS > ... #> param( ## Help content for the Param1 parameter $Param1 )
Help-specific comments must be the only comments in a comment block. If PowerShell discovers a nonhelp comment, it discontinues looking for comments in that comment block. If you need to include nonhelp comments in a comment block, place them in a separate block of comments. The following are the most typical help comments used in a comment block:
.SYNOPSIS
.DESCRIPTION
.PARAMETER
name
A description of parameter
name
, with one for each parameter you
want to describe. While you can write a
.PARAMETER
comment for each parameter,
PowerShell also supports comments written directly above the
parameter. Putting parameter help alongside the actual parameter
makes it easier to read and maintain.
.EXAMPLE
An example of this command in use,
with one for each example you want to provide. PowerShell treats
the line immediately beneath the .EXAMPLE
tag
as the example command. If this line doesn’t contain any text
that looks like a prompt, PowerShell adds a prompt before it. It
treats lines that follow the initial line as additional output
and example commentary.
.INPUTS
A short summary of pipeline input(s) supported by this command. For each input type, PowerShell’s built-in help follows this convention:
System.String You can pipe a string that contains a path to Get-ChildItem.
.OUTPUTS
A short summary of items generated by this command. For each output type, PowerShell’s built-in help follows this convention:
System.ServiceProcess.ServiceController Get-Service returns objects that represent the services on the computer.
.NOTES
.LINK
A link to a related help topic or
command, with one .LINK
tag per link. If the
related help topic is an URL, PowerShell launches that URL when
the user supplies the -Online
parameter to
Get-Help
for your command.
PowerShell supports two classes of errors:
nonterminating and terminating.
It collects both types of errors as a list in the $error
automatic variable.
Most errors are nonterminating errors, in that they do not halt execution of the current cmdlet, script, function, or pipeline. When a command outputs an error (via PowerShell’s error-output facilities), PowerShell writes that error to a stream called the error output stream.
You can output a nonterminating error using
the Write-Error
cmdlet (or
the WriteError()
API when writing a cmdlet).
The $ErrorActionPreference
automatic variable lets you control how PowerShell handles
nonterminating errors. It supports the following values, shown in Table A-14.
Most cmdlets let you configure this explicitly
by passing one of these values to the ErrorAction
parameter.
A terminating error halts execution of the current cmdlet, script, function, or pipeline. If a command (such as a cmdlet or .NET method call) generates a structured exception (for example, if you provide a method with parameters outside their valid range), PowerShell exposes this as a terminating error. PowerShell also generates a terminating error if it fails to parse an element of your script, function, or pipeline.
You can generate a terminating error in your
script using the throw
keyword:
throw message
In your own scripts and cmdlets, generate terminating errors only when the fundamental intent of the operation is impossible to accomplish. For example, failing to execute a command on a remote server should be considered a nonterminating error, whereas failing to connect to the remote server altogether should be considered a terminating error.
You can intercept terminating errors through
the try
, catch
, and
finally
statements, as supported by many other
programming languages:
try {statement block
} catch[exception type]
{error handling block
} catch[alternate exception type]
{alternate error handling block
} finally {cleanup block
}
After a try
statement, you must provide a
catch
statement, a finally
statement, or both. If you specify an exception type (which is optional), you may specify more
than one catch
statement to handle exceptions of
different types. If you specify an exception type, the
catch
block applies only to terminating errors of
that type.
PowerShell also lets you intercept terminating
errors if you define a trap
statement
before PowerShell encounters that error:
trap[exception type]
{statement block
[continue or break]
}
If you specify an exception type, the
trap
statement applies only to terminating errors of
that type.
If specified, the continue
keyword tells PowerShell to continue
processing your script, function, or pipeline after the point at which
it encountered the terminating error.
If specified, the break
keyword tells PowerShell to halt
processing the rest of your script, function, or pipeline after the
point at which it encountered the terminating error. The default mode is
break
, and it applies if you specify
neither break
nor continue
.
Pipeline
|Formatting Command
When objects reach the end of the output pipeline, PowerShell converts them to text to make them suitable for human consumption. PowerShell supports several options to help you control this formatting process, as listed in Table A-15.
Table A-15. PowerShell formatting commands
All the formatting defaults in PowerShell (for example, when you do not specify a formatting command, or when you do not specify formatting properties) are driven by the *.Format.Ps1Xml files in the installation directory in a manner similar to the type extension files mentioned in Add Custom Methods and Properties to Types.
To create your own formatting customizations,
use these files as a source of examples, but do not modify them
directly. Instead, create a new file and use the Update-FormatData
cmdlet to load your customizations. The Update-FormatData
cmdlet applies your changes
to the current instance of PowerShell. If you wish to load them every
time you launch PowerShell, call Update-FormatData
in your profile script. The
following command loads Format.custom.ps1xml from
the same directory as your profile:
$formatFile = Join-Path (Split-Path $profile) "Format.Custom.Ps1Xml" Update-FormatData -PrependPath $typesFile
There are several ways to capture the output of commands in PowerShell, as listed in Table A-16.
Table A-16. Capturing output in PowerShell
As useful as it is out of the box, PowerShell offers several avenues for customization and personalization.
The Windows PowerShell user interface offers several features to make your shell experience more efficient.
In the System menu (right-click the title bar at the top left of the console window), select Properties→Layout. The Window Size options let you control the actual window size (how big the window appears on screen), whereas the Screen Buffer Size options let you control the virtual window size (how much content the window can hold). If the screen buffer size is larger than the actual window size, the console window changes to include scrollbars. Increase the virtual window height to make PowerShell store more output from earlier in your session. If you launch PowerShell from the Start menu, PowerShell launches with some default modifications to the window size.
In the System menu, click Options→QuickEdit Mode. QuickEdit mode lets you use the mouse to efficiently copy and paste text into or out of your PowerShell console. If you launch PowerShell from the Start menu, PowerShell launches with QuickEdit mode enabled.
The Windows PowerShell console supports many hotkeys that help make operating the console more efficient, as shown in Table A-17.
Table A-17. Windows PowerShell hotkeys
While useful in their own right, the hotkeys listed in Table A-17 become even more useful when you map them to shorter or more intuitive keystrokes using a hotkey program such as the free AutoHotkey (http://www.autohotkey.com).
Windows PowerShell automatically runs the four scripts listed in Table A-18 during startup. Each, if present, lets you customize your execution environment. PowerShell runs anything you place in these files as though you had entered it manually at the command line.
Table A-18. Windows PowerShell profiles
PowerShell makes editing your profile script
simple by defining the automatic variable $profile
. By itself, it points to the “current
user, PowerShell.exe” profile. In addition, the
$profile
variable defines additional properties that
point to the other profile locations:
PS > $profile | Format-List -Force AllUsersAllHosts : C:WindowsSystem32WindowsPowerShellv1.0 profile.ps1 AllUsersCurrentHost : C:WindowsSystem32WindowsPowerShellv1.0 Microsoft.PowerShell_profile.ps1 CurrentUserAllHosts : E:LeeWindowsPowerShellprofile.ps1 CurrentUserCurrentHost : E:LeeWindowsPowerShellMicrosoft.PowerShell_ profile.ps1
To create a new profile, type:
New-Item -Type file -Force $profile
notepad $profile
To customize your prompt, add a prompt
function to your profile. This function
returns a string. For example:
function Prompt { "PS [$env:COMPUTERNAME] >" }
For more information about customizing your prompt, see also Customize Your Shell, Profile, and Prompt.
You can define a TabExpansion
function to customize the way
that Windows PowerShell completes properties, variables, parameters, and
files when you press the Tab key.
Your TabExpansion
function overrides the one that
PowerShell defines by default, though, so you may want to use its
definition as a starting point:
Get-Content function:TabExpansion
As its arguments, this function receives the entire command line as input, as well as the last word of the command line. If the function returns one or more strings, PowerShell cycles through those strings during tab completion. Otherwise, it uses its built-in logic to tab-complete filenames, directory names, cmdlet names, and variable names.
18.226.104.27