Chapter 1. PowerShell Language and Environment

Commands and Expressions

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 PowerShell interprets your statements, so Table 1-1 lists the available options.

Table 1-1. PowerShell evaluation controls
Statement Explanation

Precedence control: ()

Forces the evaluation of a command or expression, similar to the way that parentheses are used to force the order of evaluation in a mathematical expression.

For example:

PS > 5 * (1 + 2)
15
PS > (dir).Count
227

Expression subparse: $()

Forces the evaluation of a command or expression, similar to the way that parentheses are used to force the order of evaluation in a mathematical expression.

However, a subparse is as powerful as a subprogram and is required only when the subprogram contains logic or flow control statements.

This statement is also used to expand dynamic information inside a string.

For example:

PS > "The answer is (2+2)"
The answer is (2+2)

PS > "The answer is $(2+2)"
The answer is 4

PS > $value = 10
PS > $result = $(
   if($value -gt 0) { $true }
   else { $false })
PS > $result
True

List evaluation: @()

Forces an expression to be evaluated as a list. If it is already a list, it will remain a list. If it is not, PowerShell temporarily treats it as one.

For example:

PS > "Hello".Length
5
PS > @("Hello").Length
1
PS > ([PSCustomObject] @{
Property1 = "Hello"
Count = 100 }).Count
100
PS > @([PSCustomObject] @{
Property1 = "Hello"
Count = 100 }).Count
1

DATA evaluation: DATA { }

Evaluates the given script block in the context of the PowerShell data language. The data language supports only data-centric features of the PowerShell language.

For example:

PS > DATA { 1 + 1 }
2
PS > DATA { $myVariable = "Test" }
Assignment statements are not
allowed in restricted language
mode or a Data section.

Comments

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

Help Comments

PowerShell creates help for your script or function by looking at its comments. If the comments include any supported help tags, PowerShell adds those to the help for your command.

Comment-based help supports the following tags, which are all case-insensitive:

.SYNOPSIS

A short summary of the command, ideally a single sentence.

.DESCRIPTION

A more detailed description of the command.

.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
    This cmdlet returns objects that represent the
    services on the computer.
.NOTES

Any additional notes or remarks about this command.

.LINK

A link to a related help topic or command, with one .LINK tag per link. If the related help topic is a URL, PowerShell launches that URL when the user supplies the -Online parameter to Get-Help for your command.

While these are all of the supported help tags you are likely to use, comment-based help also supports tags for some of Get-Help’s more obscure features:

  • .COMPONENT

  • .ROLE

  • .FUNCTIONALITY

  • .FORWARDHELPTARGETNAME

  • .FORWARDHELPCATEGORY

  • .REMOTEHELPRUNSPACE

  • .EXTERNALHELP

For more information about these tags, type Get-Help about_Comment_Based_Help.

Variables

PowerShell provides several ways to define and access variables, as summarized in Table 1-2.

Table 1-2. PowerShell variable syntaxes
Syntax Meaning

$simpleVariable = "Value"

A simple variable name. The variable name must consist of alphanumeric characters. Variable names are not case-sensitive.

$variable1, $variable2 = "Value1", "Value2"

Multiple variable assignment. PowerShell populates each variable from the value in the corresponding position on the righthand side. Extra values are assigned as a list to the last variable listed.

${ arbitrary!@#@\#{var}iable } = "Value"

An arbitrary variable name. The variable name must be surrounded by curly braces, but it may contain any characters. Curly braces in the variable name must be escaped with a backtick (`).

${c:\filename. extension}

Variable “Get and Set Content” syntax. This is similar to the arbitrary variable name syntax. If the name corresponds to a valid PowerShell path, you can get and set the content of the item at that location by reading and writing to the variable.

[datatype] $variable = "Value"

Strongly typed variable. Ensures that the variable may contain only data of the type you declare. PowerShell throws an error if it cannot coerce the data to this type when you assign it.

[constraint] $variable = "Value"

Constrained variable. Ensures that the variable may contain only data that passes the supplied validation constraints:

[ValidateLength(4, 10)] $a = "Hello"

The supported validation constraints are the same as those supported as parameter validation attributes.

$SCOPE:variable

Gets or sets the variable at that specific scope. Valid scope names are global (to make a variable available to the entire shell), script (to make a variable available only to the current script or persistent during module commands), local (to make a variable available only to the current scope and subscopes), and private (to make a variable available only to the current scope). The default scope is the current scope: global when defined interactively in the shell, script when defined outside any functions or script blocks in a script, and local elsewhere.

New-Item Variable:\variable -Value value

Creates a new variable using the variable provider.

Get-Item Variable:\variable

Get-Variable variable

Gets the variable using the variable provider or Get-Variable cmdlet. This lets you access extra information about the variable, such as its options and description.

New-Variable variable -Option option -Value value

Creates a variable using the New-Variable cmdlet. This lets you provide extra information about the variable, such as its options and description.

Note

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

Booleans

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 1-3.

Table 1-3. PowerShell Boolean interpretations
Result Boolean representation

$true

True

$false

False

$null

False

Nonzero number

True

Zero

False

Nonempty string

True

Empty string

False

Empty array

False

Single-element array

The Boolean representation of its single element

Multi-element array

True

Hashtable (either empty or not)

True

Strings

PowerShell offers several facilities for working with plain-text data.

Literal and Expanding Strings

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'!
Note

To include a complex expression inside an expanding string, use a subexpression. For example:

$prompt = "$(Get-Location) >"

$prompt gets a value similar to c:\temp >.

Accessing the properties of an object requires a subexpression:

$version = "Current PowerShell version is:"
    $PSVersionTable.PSVersion.Major

$version gets a value similar to:

Current PowerShell version is: 3

Here Strings

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.

For example:

$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.

Escape Sequences

PowerShell supports escape sequences inside strings, as listed in Table 1-4.

Table 1-4. PowerShell escape sequences
Sequence Meaning

`0

The null character. Often used as a record separator.

`a

The alarm character. Generates a beep when displayed on the console.

`b

The backspace character. The previous character remains in the string but is overwritten when displayed on the console.

`e

The escape character. Marks the beginning of an ANSI escape sequence such as "`e[2J“.

`f

A form feed. Creates a page break when printed on most printers.

`n

A newline.

`r

A carriage return. Newlines in PowerShell are indicated entirely by the `n character, so this is rarely required.

`t

A tab.

`u{hex-code}

A unicode character literal. Creates a character represented by the specified hexadecimal Unicode code point, such as `u{2265} (≥).

`v

A vertical tab.

'' (two single quotes)

A single quote, when in a literal string.

"" (two double quotes)

A double quote, when in an expanding string.

`any other character

That character, taken literally.

Numbers

PowerShell offers several options for interacting with numbers and numeric data.

Simple Assignment

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

$myUnsignedInt = 10u
$myUnsignedInt = [uint] 10

$myInt gets the value of 10, as a (32-bit) integer. $myUnsignedInt gets the value of 10 as an unsigned 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 byte (8-bit) or short (16-bit) number, use the y or s suffixes. Prefixing either with u creates an unsigned version of that data type. You can also use the [byte], [int16], and [short] casts:

$myByte = 127y
$myByte = [byte] 127
$myUnsignedByte = 127uy

$myShort = 32767s
$myShort = [int16] 32767
$myShort = [short] 32767

$myUnsignedShort = 32767us
$myUnsignedShort = [ushort] 32767

To explicitly assign a number as a long (64-bit) integer or decimal (96-bit, 96 bits of precision), use the long (l) and decimal (d) suffixes. You can also use the [long] cast:

$myLong = 2147483648l
$myLong = [long] 2147483648

$myUnsignedLong = 2147483648ul
$myUnsignedLong = [ulong] 2147483648

$myDecimal = 0.999d

To explicitly assign a number as a BigInteger (an arbitrary large integer with no upper or lower bounds), use the BigInteger (n) suffix:

$myBigInt = 99999999999999999999999999999n

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.

Administrative Numeric Constants

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 (1,125,899,906,842,624), terabytes (1,099,511,627,776), gigabytes (1,073,741,824), megabytes (1,048,576), and kilobytes (1,024), respectively:

PS > $downloadTime = (1gb + 250mb) / 120kb
PS > $downloadTime
10871.4666666667

You can combine these numeric multipliers with a data type as long as the result fits in that data type, such as 250ngb.

Hexadecimal and Other Number Bases

To directly enter a hexadecimal number, use the hexadecimal prefix 0x:

$myErrorCode = 0xFE4A

$myErrorCode gets the integer value 65098.

To directly enter a binary number, use the binary prefix 0b:

$myBinary = 0b101101010101

$myBinary gets the integer value of 2901.

If you don’t know the hex or binary value as a constant or need to convert into Octal, use the [Convert] class from the .NET Framework. The first parameter is the value to convert, and the second parameter is the base (2, 8, 10, or 16):

$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.

Note

See “Working with the .NET Framework” to learn more about using PowerShell to interact with the .NET Framework.

Large Numbers

To work with extremely large numbers, use the BigInt class.

[BigInt]::Pow(12345, 123)

To do math with several large numbers, use the [BigInt] cast (or the n BigInt data type) for all operands:

PS > 98123498123498123894n * 98123498123498123894n
9628220883992139841085109029337773723236

PS > $val = "98123498123498123894"
PS > ([BigInt] $val) * ([BigInt] $val)
9628220883992139841085109029337773723236

Imaginary and Complex Numbers

To work with imaginary and complex numbers, use the System.Numerics.Complex class:

PS > [System.Numerics.Complex]::ImaginaryOne *
    [System.Numerics.Complex]::ImaginaryOne | Format-List

Real      : -1
Imaginary : 0
Magnitude : 1
Phase     : 3.14159265358979

Arrays and Lists

Array Definitions

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 don’t 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
Note

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

Array Access

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 negative, and the second number in the range is positive.

PS > $myArray[-1..-3]
6
5
4

returns the last element of the array through to the third-to-last element in the 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.

If the array being accessed might be null, you can use the null conditional array access operator (?[]). The result of the expression will be null if the array being accessed did not exist. It will be the element at the specified index otherwise:

(Get-Process -id 0).Modules?[0]

Array Slicing

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.

Note

You can use the array slicing syntax to create arrays as well:

$myArray = ,0+2..3+0,0

Hashtables (Associative Arrays)

Hashtable Definitions

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" }

To define a hashtable that retains its insertion order, use the [ordered] cast:

$orderedHash = [ordered] @{}
$orderedHash["NewKey"] = "Value"

Hashtable Access

To access or modify a specific element in an associative array, you can use either the array-access or property-access syntax:

$myHashtable["Key1"]

returns "Value1".

$myHashtable."Key 2"

returns the array 1,2,3.

$myHashtable["New Item"] = 5

adds "New Item" to the hashtable.

$myHashtable."New Item" = 5

also adds "New Item" to the hashtable.

XML

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.

Simple Operators

Once you have defined your data, the next step is to work with it.

Arithmetic Operators

The arithmetic operators let you perform mathematical operations on your data, as shown in Table 1-5.

Note

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 1-5. PowerShell arithmetic operators
Operator Meaning

+

The addition operator:

$leftValue + $rightValue

When used with numbers, returns their sum.

When used with strings, returns a new string created by appending the second string to the first.

When used with arrays, returns a new array created by appending the second array to the first.

When used with hashtables, returns a new hashtable created by merging the two hashtables. Since hashtable keys must be unique, PowerShell returns an error if the second hashtable includes any keys already defined in the first hashtable.

When used with any other type, PowerShell uses that type’s addition operator (op_Addition) if it implements one.

The subtraction operator:

$leftValue - $rightValue

When used with numbers, returns their difference.

This operator does not apply to strings, arrays, or hashtables.

When used with any other type, PowerShell uses that type’s subtraction operator (op_Subtraction) if it implements one.

*

The multiplication operator:

$leftValue * $rightValue

When used with numbers, returns their product.

When used with strings ("=" * 80), returns a new string created by appending the string to itself the number of times you specify.

When used with arrays (1..3 * 7), returns a new array created by appending the array to itself the number of times you specify.

This operator does not apply to hashtables.

When used with any other type, PowerShell uses that type’s multiplication operator (op_Multiply) if it implements one.

/

The division operator:

$leftValue / $rightValue

When used with numbers, returns their quotient.

This operator does not apply to strings, arrays, or hashtables.

When used with any other type, PowerShell uses that type’s division operator (op_Division) if it implements one.

%

The modulus operator:

$leftValue % $rightValue

When used with numbers, returns the remainder of their division.

This operator does not apply to strings, arrays, or hashtables.

When used with any other type, PowerShell uses that type’s modulus operator (op_Modulus) if it implements one.

+=

-=

*=

/=

%=

Assignment operators:

$variable operator= value

These operators match the simple arithmetic operators (+, –, *, /, and %) but store the result in the variable on the lefthand side of the operator. It is a short form for

$variable = $variable operator value.

Logical Operators

The logical operators let you compare Boolean values, as shown in Table 1-6.

Table 1-6. PowerShell logical operators
Operator Meaning

-and

Logical AND:

$leftValue -and $rightValue

Returns $true if both lefthand and righthand arguments evaluate to $true. Returns $false otherwise.

You can combine several -and operators in the same expression:

$value1 -and $value2 -and $value3 …

PowerShell implements the -and operator as a short-circuit operator and evaluates arguments only if all arguments preceding it evaluate to $true.

-or

Logical OR:

$leftValue -or $rightValue

Returns $true if the lefthand or righthand arguments evaluate to $true. Returns $false otherwise.

You can combine several -or operators in the same expression:

$value1 -or $value2 -or $value3 ...

PowerShell implements the -or operator as a short-circuit operator and evaluates arguments only if all arguments preceding it evaluate to $false.

-xor

Logical exclusive OR:

$leftValue -xor $rightValue

Returns $true if either the lefthand or righthand argument evaluates to $true, but not if both do.

Returns $false otherwise.

-not

!

Logical NOT:

-not $value

Returns $true if its righthand (and only) argument evaluates to $false. Returns $false otherwise.

Binary Operators

The binary operators, listed in Table 1-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 1-7. PowerShell binary operators
Operator Meaning

-band

Binary AND:

$leftValue -band $rightValue

Returns a number where bits are set to 1 if the bits of the lefthand and righthand arguments at that position are both 1. All other bits are set to 0. For example:

PS > $int1 = 0b110110110
PS > $int2 = 0b010010010
PS > $result = $int1 -band $int2
PS > [Convert]::ToString($result, 2)
10010010

-bor

Binary OR:

$leftValue -bor $rightValue

Returns a number where bits are set to 1 if either of the bits of the lefthand and righthand arguments at that position is 1. All other bits are set to 0. For example:

PS > $int1 = 0b110110110
PS > $int2 = 0b010010010
PS > $result = $int1 -bor $int2
PS > [Convert]::ToString($result, 2)
110110110

-bxor

Binary exclusive OR:

$leftValue -bxor $rightValue

Returns a number where bits are set to 1 if either of the bits of the lefthand and righthand arguments at that position is 1, but not if both are. All other bits are set to 0. For example:

PS > $int1 = 0b110110110
PS > $int2 = 0b010010010
PS > $result = $int1 -bxor $int2
PS > [Convert]::ToString($result, 2)
100100100

-bnot

Binary NOT:

-bnot $value

Returns a number where bits are set to 1 if the bit of the righthand (and only) argument at that position is set to 1. All other bits are set to 0. For example:

PS > $int1 = 0b110110110
PS > $result = -bnot $int1
PS > [Convert]::ToString($result, 2)
11111111111111111111111001001001

-shl

Binary shift left:

$value -slh $count

Shifts the bits of a number to the left $count places. Bits on the righthand side are set to 0. For example:

PS > $int1 = 438
PS > [Convert]::ToString($int1, 2)
110110110

PS > $result = $int1 -shl 5
PS > [Convert]::ToString($result, 2)
11011011000000

-shr

Binary shift right:

$value -slr $count

Shifts the bits of a number to the right $count places. For signed values, bits on the lefthand side have their sign preserved. For example:

PS > $int1 = -2345
PS > [Convert]::ToString($int1, 2)
11111111111111111111011011010111

PS > $result = $int1 -shr 3
PS > [Convert]::ToString($result, 2)
11111111111111111111111011011010

Other Operators

PowerShell supports several other simple operators, as listed here.

-replace (Replace operator)

The replace operator returns a new string, where the text in "target" that matches the regular expression "pattern" has been replaced with the replacement text "replacement":

"target" -replace "pattern","replacement"

The following returns a new string, where the text in "target" that matches the regular expression "pattern" has been replaced with the output value of the script block supplied. In the script block, the $_ variable represents the current System.Text.RegularExpressions.Match:

"target" -replace "pattern",{ scriptblock }

By default, PowerShell performs a case-insensitive comparison. The -ireplace operator makes this case-insensitivity explicit, whereas the -creplace operator performs a case-sensitive comparison.

If the regular expression pattern contains named captures or capture groups, the replacement string may reference those as well. For example:

PS > "Hello World" -replace "(.*) (.*)",'$2 $1'
World Hello

If "target" represents an array, the -replace operator operates on each element of that array.

For more information on the details of regular expressions, see Chapter 2.

-f (Format operator)

The format operator 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:

"Format String" -f values

For example:

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 String.Format method.

For more details about the syntax of the format string, see Chapter 4.

-as (Type conversion operator)

The type conversion operator returns $value cast to the given .NET type:

$value -as [Type]

If this conversion is not possible, PowerShell returns $null. For example:

PS > 3/2 -as [int]
2
PS > $result = "Hello" -as [int]
PS > $result -eq $null
True

-split (Split operator)

The unary split operator breaks the given input string into an array, using whitespace (\s+) to identify the boundary between elements:

-split "Input String"

It also trims the results. For example:

PS > -split "  Hello    World   "
Hello
World

The binary split operator breaks the given input string into an array, using the given delimiter or script block to identify the boundary between elements:

"Input String" -split "delimiter",maximum,options
"Input String" -split { Scriptblock },maximum

Delimiter is interpreted as a regular expression match. Scriptblock is called for each character in the input, and a split is introduced when it returns $true.

Maximum defines the maximum number of elements to be returned, leaving unsplit elements as the last item. This item is optional. Use "0" for unlimited if you want to provide options but not alter the maximum.

Options define special behavior to apply to the splitting behavior. The possible enumeration values are:

SimpleMatch

Split on literal strings, rather than regular expressions they may represent.

RegexMatch

Split on regular expressions. This option is the default.

CultureInvariant

Does not use culture-specific capitalization rules when doing a case-insensitive split.

IgnorePatternWhitespace

Ignores spaces and regular expression comments in the split pattern.

Multiline

Allows the ^ and $ characters to match line boundaries, not just the beginning and end of the content.

Singleline

Treats the ^ and $ characters as the beginning and end of the content. This option is the default.

IgnoreCase

Ignores the capitalization of the content when searching for matches.

ExplicitCapture

In a regular expression match, only captures named groups. This option has no impact on the -split operator.

For example:

PS > "1a2B3" -split "[a-z]+",0,"IgnoreCase"
1
2
3

-join (Join operator)

The unary join operator combines the supplied items into a single string, using no separator:

-join ("item1","item2",...,"item_n")

For example:

PS > -join ("a","b")
ab

The binary join operator combines the supplied items into a single string, using Delimiter as the separator:

("item1","item2",...,"item_n") -join Delimiter

For example:

PS > ("a","b") -join ", "
a, b

Comparison Operators

The PowerShell comparison operators, listed in Table 1-8, 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 1-8. PowerShell comparison operators
Operator Meaning

-eq

The equality operator:

$leftValue -eq $rightValue

For all primitive types, returns $true if $leftValue and $rightValue are equal.

When used with arrays, returns all elements in $leftValue that are equal to $rightValue.

When used with any other type, PowerShell uses that type’s Equals() method if it implements one.

-ne

The negated equality operator:

$leftValue -ne $rightValue

For all primitive types, returns $true if$leftValue and $rightValue are not equal.

When used with arrays, returns all elements in $leftValue that are not equal to$rightValue.

When used with any other type, PowerShell returns the negation of that type’s Equals() method if it implements one.

-ge

The greater-than-or-equal operator:

$leftValue -ge $rightValue

For all primitive types, returns $true if $leftValue is greater than or equal to $rightValue.

When used with arrays, returns all elements in $leftValue that are greater than or equal to $rightValue.

When used with any other type, PowerShell returns the result of that object’s Compare() method if it implements one. If the method returns a number greater than or equal to zero, the operator returns $true.

-gt

The greater-than operator:

$leftValue -gt $rightValue

For all primitive types, returns $true if $leftValue is greater than $rightValue.

When used with arrays, returns all elements in $leftValue that are greater than $rightValue.

When used with any other type, PowerShell returns the result of that object’s Compare() method if it implements one. If the method returns a number greater than zero, the operator returns $true.

-in

The in operator:

$value -in $list

Returns $true if the value $value is contained in the list $list. That is, if $item -eq $value returns $true for at least one item in the list. This is equivalent to the -contains operator with the operands reversed.

-notin

The negated in operator:

Returns $true when the -in operator would return $false.

-lt

The less-than operator:

$leftValue -lt $rightValue

For all primitive types, returns $true if $leftValue is less than $rightValue.

When used with arrays, returns all elements in $leftValue that are less than $rightValue.

When used with any other type, PowerShell returns the result of that object’s Compare() method if it implements one. If the method returns a number less than zero, the operator returns $true.

-le

The less-than-or-equal operator:

$leftValue -le $rightValue

For all primitive types, returns $true if $leftValue is less than or equal to$rightValue.

When used with arrays, returns all elements in $leftValue that are less than or equal to $rightValue.

When used with any other type, PowerShell returns the result of that object’s Compare() method if it implements one. If the method returns a number less than or equal to zero, the operator returns $true.

-like

The like operator:

$leftValue -like Pattern

Evaluates the pattern against the target, returning $true if the simple match is successful.

When used with arrays, returns all elements in $leftValue that match Pattern.

The -like operator supports the following simple wildcard characters:

  • ?: Any single unspecified character

  • *: Zero or more unspecified characters

  • [a-b]: Any character in the range of a–b

  • [ab]: The specified characters a or b

For example:

PS > "Test" -like "[A-Z]e?[tr]"
True

-notlike

The negated like operator:

Returns $true when the -like operator would return $false.

-match

The match operator:

"Target" -match Regular Expression

Evaluates the regular expression against the target, returning $true if the match is successful. Once complete, PowerShell places the successful matches in the $matches variable.

When used with arrays, returns all elements in Target that match Regular Expression.

The $matches variable is a hashtable that maps the individual matches to the text they match. 0 is the entire text of the match, 1 and on contain the text from any unnamed captures in the regular expression, and string values contain the text from any named captures in the regular expression.

For example:

PS > "Hello World" -match "(.*) (.*)"
True
PS > $matches[1]
Hello

For more information on the details of regular expressions, see Chapter 2.

-notmatch

The negated match operator:

Returns $true when the -match operator would return $false.

The -notmatch operator still populates the $matches variable with the results of match.

-contains

The contains operator:

$list -contains $value

Returns $true if the list specified by $list contains the value $value—that is, if $item -eq $value returns $true for at least one item in the list. This is equivalent to the -in operator with the operands reversed.

-notcontains

The negated contains operator:

Returns $true when the -contains operator would return $false.

-is

The type operator:

$leftValue -is [type]

Returns $true if $value is (or extends) the specified .NET type.

-isnot

The negated type operator:

Returns $true when the -is operator would return $false.

Conditional Statements

Conditional statements in PowerShell let you change the flow of execution in your script.

if, elseif, and else Statements

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.

Note

See “Simple Operators” and “Comparison Operators” for 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.

For example:

$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.

To apply an if statement to each element of a list and filter it to return only the results that match the supplied condition, use the Where-Object cmdlet or .where() method:

Get-Process | Where-Object { $_.Handles -gt 500 }

(Get-Process).where( { $_.Handles -gt 500} )

Ternary Operators

$result = condition ? true value : false value

A short-form version of an if/else statement. If condition evaluates to $true, the result of the expression is the value of the true value clause. Otherwise, the result of the expression is the value of the false value clause. For example:

(Get-Random) % 2 -eq 0 ? "Even number" : "Odd number"

Null Coalescing and Assignment Operators

$result = nullable value ?? default value

Assignment version:

$result = nullable value
$result ??= default value

A short-form version of a ternary operator that only checks if the expression is null or not. If it is null, the result of the expression is the value of the default value clause. For example:

Get-Process | ForEach-Object { $_.CPU ?? "<Unavailable>" }

or

$cpu = (Get-Process -id 0).CPU
$cpu ??= "Unavailable"

switch Statements

switch options expression
{
   comparison value           { statement block }
   -or-
   { comparison expression }  { statement block }
   (...)
   default                    { statement block }
}

or:

switch options -file filename
{
   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 1-9.

Table 1-9. Options supported by PowerShell switch statements
Option Meaning

-casesensitive

-c

Case-sensitive match.

With this option active, PowerShell executes the associated statement block only if the current input item exactly matches the value specified by comparison value. If the current input object is a string, the match is case-sensitive.

-exact

-e

Exact match

With this option active, PowerShell executes the associated statement block only if the current input item exactly matches the value specified by comparison value. This match is case-insensitive. This is the default mode of operation.

-regex

-r

Regular-expression match

With this option active, PowerShell executes the associated statement block only if the current input item matches the regular expression specified by comparison value. This match is case-insensitive.

-wildcard

-w

Wildcard match

With this option active, PowerShell executes the associated statement block only if the current input item matches the wildcard specified by comparison value.

The wildcard match supports the following simple wildcard characters:

  • ?: Any single unspecified character

  • *: Zero or more unspecified characters

  • [a-b]: Any character in the range of a–b

  • [ab]: The specified characters a or b

This match is case-insensitive.

The { comparison expression } statements let you process the current input item, which is stored in the $_ (or $PSItem) 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.

For example:

$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" }
}

produces the output:

Area code was specified
In the 555 area code
Area code was not specified
Note

See the next section on 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

Looping statements in PowerShell let you execute groups of statements multiple times.

for Statement

: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 example:

for($counter = 0; $counter -lt 10; $counter++)
{
    Write-Host "Processing item $counter"
}

The break and continue statements (discussed in “Flow Control Statements”) can specify the loop_label of any enclosing looping statement as their target.

foreach Statement

: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

In addition to the foreach statement, you can also use the foreach method on collections directly:

$handleSum = 0
(Get-Process).foreach( { $handleSum += $_.Handles } )

The break and continue statements (discussed in “Flow Control Statements”) 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.

while Statement

: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 in “Flow Control Statements”) can specify the loop_label of any enclosing looping statement as their target.

do … while Statement/do … until Statement

:loop_label do
{
   statement block
} while(condition)

or

: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 $response"

$response = ""
do
{
   $response = Read-Host "Yes or No?"
} until($validResponses -contains $response)
"Got $response"

The break and continue statements (discussed in the next section) can specify the loop_label of any enclosing looping statement as their target.

Flow Control Statements

PowerShell supports two statements to help you control flow within loops: break and continue.

break

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 (notice the second column never reaches the value 2):

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"
    }
}

produces the output:

Processing item 0,0
Processing item 0,1

continue

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"
    }
}

produces the output:

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.

For example:

: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"
    }
}

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

Classes

## A class called "Example" that inherits from "BaseClass"
## and implements the "ImplementedInterface" interface
class Example : BaseClass, ImplementedInterface
{
    ## Default constructor, which also invokes the constructor
    ## from the base class.
    Example() : base()
    {
        [Example]::lastInstantiated = Get-Date
    }

    ## Constructor with parameters
    Example([string] $Name)
    {
        $this.Name = $Name
        [Example]::lastInstantiated = Get-Date
    }

    ## A publicly visible property with validation attributes
    [ValidateLength(2,20)]
    [string] $Name

    ## A property that is hidden from default views
    static hidden [DateTime] $lastInstantiated

    ## A publicly visible method that returns a value
    [string] ToString()
    {
        ## Return statement is required. Implicit / pipeline output
        ## is not treated as output like it is with functions.
        return $this.ToString( [Int32]::MaxValue )
    }

    ## A publicly visible method that returns a value
    [string] ToString([int] $MaxLength)
    {
        $output = "Name = $($this.Name);"
            "LastInstantiated = $([Example]::lastInstantiated)"
        $outputLength = [Math]::Min($MaxLength, $output.Length)
        return $output.Substring(0, $outputLength)
    }

}

Base classes and interfaces

To define a class that inherits from a base class or implements an interfaces, provide the base class and/or interface names after the class name, separated by a colon (deriving from a base class or implementing any interfaces is optional):

class Example [: BaseClass, ImplementedInterface]

Constructors

To define a class constructor, create a method with the same name as the class. You can define several constructors, including those with parameters. To automatically call a constructor from the base class, add : base() to the end of the method name:

Example() [: base()]

Example([int] $Parameter1, [string] $Parameter2) [: base()]

Properties

To define a publicly visible property, define a PowerShell variable in your class. As with regular Powershell variables, you may optionally add validation attributes or declare a type constraint for the property:

[ValidateLength(2,20)]
[string] $Name

To hide the property from default views (similar to a member variable in other languages), use the hidden keyword. Users are still able to access hidden properties if desired: they are just removed from default views. You can make a property static if you want it to be shared with all instances of your class in the current process:

static hidden [DateTime] $lastInstantiated

Methods

Define a method as though you would define a PowerShell function, but without the function keyword and without the param() statement. Methods support parameters, parameter validation, and can also have the same name as long as their parameters differ:

[string] ToString() { ... }

[string] ToString([int] $MaxLength) { ... }

Custom Enumerations

To define a custom enumeration, use the enum keyword:

enum MyColor {
  Red = 1
  Green = 2
  Blue = 3
}

If enumeration values are intended to be combined through bitwise operators, use the [Flags()] attribute. If you require that the enumerated values derive from a specific integral data type (byte, sbyte, short, ushort, int, uint, long or ulong), provide that data type after the colon character:

[Flags()] enum MyColor : uint {
  Red = 1
  Green = 2
  Blue = 4
}

Workflow-Specific Statements

Within a workflow, PowerShell supports three statements not supported in traditional PowerShell scripts: InlineScript, Parallel, and Sequence.

Note

Workflows are no longer supported in PowerShell. This section exists to help you understand and interact with workflows that have already been written.

InlineScript

The InlineScript keyword defines an island of PowerShell script that will be invoked as a unit, and with traditional PowerShell scripting semantics. For example:

workflow MyWorkflow
{
    ## Method invocation not supported in a workflow
    ## [Math]::Sqrt(100)

    InlineScript
    {
        ## Supported in an InlineScript
        [Math]::Sqrt(100)
    }
}

Parallel/Sequence

The Parallel keyword specifies that all statements within the statement block should run in parallel. To group statements that should be run as a unit, use the Sequence keyword:

workflow MyWorkflow
{
    Parallel
    {
        InlineScript { Start-Sleep -Seconds 2;
            "One thing run in parallel" }
        InlineScript { Start-Sleep -Seconds 4;
            "Another thing run in parallel" }
        InlineScript { Start-Sleep -Seconds 3;
            "A third thing run in parallel" }

        Sequence
        {
            Start-Sleep -Seconds 1
            "A fourth"
            "and fifth thing run as a unit, in parallel"
        }
    }
}

Note that you should not use PowerShell Workflows for the parallel statement alone—the -Parallel parameter to the ForEach-Object cmdlet is much more efficient.

Working with the .NET Framework

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.

Working with the .NET Framework in PowerShell comes mainly by way of one of two tasks: calling methods or accessing properties.

Static Methods

To call a static method on a class, type:

[ClassName]::MethodName(parameter list)

For example:

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

Instance Methods

To call a method on an instance of an object, type:

$objectReference.MethodName(parameter list)

For example:

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.

Explicitly Implemented Interface Methods

To call a method on an explictly implemented interface, type:

([Interface] $objectReference).MethodName(parameter list)

For example:

PS > ([IConvertible] 123).ToUint16($null)

Static Properties

To access a static property on a class, type:

[ClassName]::PropertyName

or:

[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.

Instance Properties

To access an instance property on an object, type:

$objectReference.PropertyName

or:

$objectReference.PropertyName = value

For example:

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.

If the value of the property might be null, you can use the null conditional property access operator (?.). The result of the expression will be null if any property in the chain did not exist. It will be the final property’s value otherwise:

(Get-Process -id 0)?.MainModule?.Filename

Learning About Types

The two primary avenues for learning about classes and types are the Get-Member cmdlet and the documentation for the .NET Framework.

The Get-Member cmdlet

To learn what methods and properties a given type supports, pass it through the Get-Member cmdlet, as shown in Table 1-10.

Table 1-10. Working with the Get-Member cmdlet
Action Result

[typename] | Get-Member-Static

All the static methods and properties of a given type.

$objectReference | Get-Member-Static

All the static methods and properties provided by the type in $objectReference.

$objectReference | Get-Member

All the instance methods and properties provided by the type in $objectReference. If $objectReference represents a collection of items, PowerShell returns the instances and properties of the types contained by that collection. To view the instances and properties of a collection itself, use the -InputObject parameter of Get-Member:

Get-Member -InputObject $objectReference

[typename] | Get-Member

All the instance methods and properties of a System.RuntimeType object that represents this type.

.NET Framework documentation

Another source of information about the classes in the .NET Framework is the documentation itself, available through the search facilities at Microsoft’s developer documentation site.

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.

Note

To get to the documentation for the members quickly, search for them more explicitly by adding the term “members” to your 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.

Type Shortcuts

When you specify a type name, PowerShell lets you use a short form for some of the most common types, as listed in Table 1-11.

Table 1-11. PowerShell type shortcuts
Type shortcut Full classname

[Adsi]

[System.DirectoryServices.​DirectoryEntry]

[AdsiSearcher]

[System.DirectoryServices.​DirectorySearcher]

[Float]

[System.Single]

[Hashtable]

[System.Collections.Hashtable]

[Int]

[System.Int32]

[IPAddress]

[System.Net.IPAddress]

[Long]

[System.Collections.Int64]

[PowerShell]

[System.Management.Automation.​PowerShell]

[PSCustomObject]

[System.Management.Automation.​PSObject]

[PSModuleInfo]

[System.Management.Automation.​PSModuleInfo]

[PSObject]

[System.Management.Automation.​PSObject]

[Ref]

[System.Management.Automation.​PSReference]

[Regex]

[System.Text.RegularExpressions.​Regex]

[Runspace]

[System.Management.Automation.​Runspaces.Runspace]

[Runspace​Factory]

[System.Management.Automation.​Runspaces.RunspaceFactory]

[ScriptBlock]

[System.Management.Automation.​ScriptBlock]

[Switch]

[System.Management.Automation.​SwitchParameter]

[Wmi]

[System.Management.ManagementObject]

[WmiClass]

[System.Management.ManagementClass]

[WmiSearcher]

[System.Management.​ManagementObjectSearcher]

[Xml]

[System.Xml.XmlDocument]

[TypeName]

[System.TypeName]

Creating Instances of Types

$objectReference = New-Object TypeName parameters
$objectReference = [TypeName]::new(parameters)

Although static methods and properties of a class generate objects, you’ll 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 described in the SDK documentation.

For example:

$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 Microsoft 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 > [System.Web.HttpUtility]::UrlEncode("http://www.bing.com")
http%3a%2f%2fwww.bing.com

To update the list of namespaces that PowerShell searches by default, specify that namespace in a using statement:

PS > using namespace System.Web
PS > [HttpUtility]::UrlEncode("http://www.bing.com")

Interacting with COM Objects

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 Chapter 8.

Extending Types

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

The Add-Member cmdlet lets you dynamically add methods, properties, and more to an object. It supports the extensions shown in Table 1-12.

Table 1-12. Selected member types supported by the Add-Member cmdlet
Member type Meaning

AliasProperty

A property defined to alias another property:

PS > $testObject = [PsObject] "Test"
PS > $testObject |
    Add-Member "AliasProperty" Count Length
PS > $testObject.Count
4

CodeProperty

A property defined by a System.Reflection.​Meth⁠odInfo.

This method must be public, static, return results (nonvoid), and take one parameter of type PsObject.

NoteProperty

A property defined by the initial value you provide:

PS > $testObject = [PsObject] "Test"
PS > $testObject |
    Add-Member NoteProperty Reversed tseT
PS > $testObject.Reversed
tseT

ScriptProperty

A property defined by the script block you provide. In that script block, $this refers to the current instance:

PS > $testObject = [PsObject] ("Hi" * 100)
PS > $testObject |
    Add-Member ScriptProperty IsLong {
      $this.Length -gt 100
   }
PS > $testObject.IsLong

True

PropertySet

A property defined as a shortcut to a set of properties. Used in cmdlets such as Select-Object:

PS > $testObject = [PsObject] [DateTime]::Now
PS > $collection = New-Object `
 Collections.ObjectModel.Collection[String]
$collection.Add("Month")
$collection.Add("Year")
$testObject |
 Add-Member PropertySet MonthYear $collection
$testObject | select MonthYear


Month                                   Year
-----                                   ----
    3                                   2010

CodeMethod

A method defined by a System.Reflection.​Meth⁠odInfo.

This method must be public, static, and take one parameter of type PsObject.

ScriptMethod

A method defined by the script block you provide. In that script block, $this refers to the current instance, and $args refers to the input parameters:

PS > $testObject = [PsObject] "Hello"
PS > $testObject |
    Add-Member ScriptMethod IsLong {
      $this.Length -gt $args[0]
   }
PS > $testObject.IsLong(3)
True

PS > $testObject.IsLong(100)
False

Custom type extension files

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 documentation URLs) 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

Writing Scripts, Reusing Functionality

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.

Writing Commands

Writing scripts

To write a script, write your PowerShell commands in a text editor and save the file with a .ps1 extension.

Writing functions

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
}

or:

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.

Note

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”.

Note

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

Writing script blocks

$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.

Running Commands

There are two ways to execute a command (script, function, or script block): by invoking it or by dot-sourcing it.

Invoking

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.

Note

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:\temp\Invoke-Commands.ps1 parameter1 parameter2 ...
Invoke-MyFunction parameter1 parameter2 ...

To run the command as a background job, use the background operator (&):

c:\temp\Invoke-Commands.ps1 parameter1 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:\My Scripts\Invoke-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-MyFunction parameter1 parameter2 ...
& $module $scriptBlock parameter1 parameter2 ...

Dot-sourcing

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 Directory\Invoke-Commands.ps1" Parameters
. Invoke-MyFunction parameters
. $scriptBlock parameters

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-MyFunction parameters
. $module $scriptBlock parameters

Parameters

Commands that require or support user input do so through parameters. You can use the Get-Command cmdlet to see the parameters supported by a command:

PS > Get-Command Stop-Process -Syntax

Stop-Process [-Id] <int[]> [-PassThru] [-Force] [-WhatIf] [...]
Stop-Process -Name <string[]> [-PassThru] [-Force] [-WhatIf] [...]
Stop-Process [-InputObject] <Process[]> [-PassThru] [-Force] [...]

In this case, the supported parameters of the Stop-Process command are Id, Name, InputObject, PassThru, Force, WhatIf, and Confirm.

To supply a value for a parameter, use a dash character, followed by the parameter name, followed by a space, and then the parameter value:

Stop-Process -Id 1234

If the parameter value contains spaces, surround it with quotes:

Stop-Process -Name "Process With Spaces"

If a variable contains a value that you want to use for a parameter, supply that through PowerShell’s regular variable reference syntax:

$name = "Process With Spaces"
Stop-Process -Name $name

If you want to use other PowerShell language elements as a parameter value, surround the value with parentheses:

Get-Process -Name ("Power" + "Shell")

You only need to supply enough of the parameter name to disambiguate it from the rest of the parameters:

Stop-Process -N "Process With Spaces"

If a command’s syntax shows the parameter name in square brackets (such as [-Id]), then it is positional and you may omit the parameter name and supply only the value. PowerShell supplies these unnamed values to parameters in the order of their position:

Stop-Process 1234

Rather than explicitly providing parameter names and values, you can provide a hashtable that defines them and use the splatting operator:

$parameters = @{
   Path = "c:\temp"
   Recurse = $true
}

Get-ChildItem @parameters

To define the default value to be used for the parameter of a command (if the parameter value is not specified directly), assign a value to the PSDefaultParameterValues hashtable. The keys of this hashtable are command names and parameter names, separated by a colon. Either (or both) may use wildcards. The values of this hashtable are either simple parameter values, or script blocks that will be evaluated dynamically:

PS > $PSDefaultParameterValues["Get-Process:ID"] = $pid
PS > Get-Process

PS > $PSDefaultParameterValues["Get-Service:Name"] = {
    Get-Service -Name * | ForEach-Object Name | Get-Random }
PS > Get-Service

Providing Input to Commands

PowerShell offers several options for processing input to a command.

Argument array

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

Formal parameters

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.

Command behavior customizations

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.

Parameter attribute customizations

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 -Param1 Argument1 Argument2). PowerShell supplies these values to parameters that have defined a 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.

Parameter validation attributes

In addition to the [Parameter()] attribute, PowerShell lets you apply other attributes that add 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 $_ (or $PSItem) 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.

Pipeline input

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)

Cmdlet keywords in commands

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 $_ (or $PSItem) 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.

$MyInvocation automatic variable

The $MyInvocation automatic variable contains information about the context under which the script was run, including detailed information about the command (MyCommand), the script that defines it (ScriptName), and more.

Retrieving Output from Commands

PowerShell provides three primary ways to retrieve output from a command.

Pipeline output

any command

The return value/output of a script is any data that it generates but does not capture. If a command contains:

"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.

Return statement

return value

The statement:

return $false

is simply a short form for pipeline output:

$false
return

Exit statement

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.

Note

Type Get-Help about_automatic_variables for more information about automatic variables.

Managing Errors

PowerShell supports two classes of errors: nonterminating and terminating. It collects both types of errors as a list in the $error automatic variable.

Nonterminating Errors

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 1-13.

Table 1-13. ErrorActionPreference automatic variable values
Value Meaning

Ignore

Do not display errors, and do not add them to the $error collection. Only supported when supplied to the ErrorAction parameter of a command.

SilentlyContinue

Do not display errors, but add them to the $error collection.

Stop

Treat nonterminating errors as terminating errors.

Continue

Display errors, but continue execution of the current cmdlet, script, function, or pipeline. This is the default.

Inquire

Display a prompt that asks how PowerShell should treat this error.

Most cmdlets let you configure this explicitly by passing one of these values to the ErrorAction parameter.

Terminating Errors

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
Note

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.

Within a catch block or trap statement, the $_ (or $PSItem) variable represents the current exception or error being processed.

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.

Formatting Output

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 1-14.

Table 1-14. PowerShell formatting commands
Formatting command Result

Format-Table

Formats the properties of the input objects as a table, including only the object properties you specify. If you do not specify a property list, PowerShell picks a default set.

In addition to supplying object properties, you may also provide advanced formatting statements:

PS > Get-Process | `
   Format-Table -Auto Name,`
   @{Label="HexId";
     Expression={ "{0:x}" -f $_.Id}
     Width=4
     Align="Right"
    }

The advanced formatting statement is a hashtable with the keys Label and Expression (or any short form of them). The value of the expression key should be a script block that returns a result for the current object (represented by the $_ variable).

For more information about the Format-Table cmdlet, type Get-Help Format-Table.

Format-List

Formats the properties of the input objects as a list, including only the object properties you specify. If you do not specify a property list, PowerShell picks a default set.

The Format-List cmdlet supports advanced formatting statements as used by the Format-Table cmdlet.

The Format-List cmdlet is the one you will use most often to get a detailed summary of an object’s properties.

The command Format-List * returns all properties, but it does not include those that PowerShell hides by default. The command Format-List * -Force returns all properties.

For more information about the Format-List cmdlet, type Get-Help Format-List.

Format-Wide

Formats the properties of the input objects in an extremely terse summary view. If you do not specify a property, PowerShell picks a default.

In addition to supplying object properties, you can also provide advanced formatting statements:

PS > Get-Process | `
   Format-Wide -Auto `
   @{ Expression={ "{0:x}" -f $_.Id} }

The advanced formatting statement is a hashtable with the key Expression (or any short form of it). The value of the expression key should be a script block that returns a result for the current object (represented by the $_ variable).

For more information about the Format-Wide cmdlet, type Get-Help Format-Wide.

Custom Formatting Files

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.

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 $formatFile

Capturing Output

There are several ways to capture the output of commands in PowerShell, as listed in Table 1-15.

Table 1-15. Capturing output in PowerShell
Command Result

$variable = Command

Stores the objects produced by the PowerShell command into $variable.

$variable = Command | Out-String

Stores the visual representation of the PowerShell command into $variable. This is the PowerShell command after it’s been converted to human-readable output.

$variable = NativeCommand

Stores the (string) output of the native command into $variable. PowerShell stores this as a list of strings—one for each line of output from the native command.

Command -OutVariable variable

For most commands, stores the objects produced by the PowerShell command into $variable. The parameter -OutVariable can also be written -Ov.

Command > File

Redirects the visual representation of the PowerShell (or standard output of a native command) into File, overwriting File if it exists. Errors are not captured by this redirection.

Command >> File

Redirects the visual representation of the PowerShell (or standard output of a native command) into File, appending to File if it exists. Errors are not captured by this redirection.

Command 2> File

Redirects the errors from the PowerShell or native command into File, overwriting File if it exists.

Command n>File

Redirects stream number n into File, overwriting File if it exists. Supported streams are 2 for error, 3 for warning, 4 for verbose, 5 for debug, 6 for the structured information stream, and * for all.

Command 2>> File

Redirects the errors from the PowerShell or native command into File, appending to File if it exists.

Command n>> File

Redirects stream number n into File, appending to File if it exists. Supported streams are 2 for error, 3 for warning, 4 for verbose, 5 for debug, 6 for the structured information stream, and * for all.

Command > File 2>&1

Redirects both the error and standard output streams of the PowerShell or native command into File, overwriting File if it exists.

Command >> File 2>&1

Redirects both the error and standard output streams of the PowerShell or native command into File, appending to File if it exists.

While output from the Write-Host cmdlet normally goes directly to the screen, you can use the structured information stream to capture it into a variable:

PS > function HostWriter { Write-Host "Console Output" }
PS > $a = HostWriter
Console Output
PS > $a
PS > $a = HostWriter 6>&1
PS > $a
Console Output

Common Customization Points

As useful as it is out of the box, PowerShell offers several avenues for customization and personalization.

Console Settings

The Windows PowerShell user interface offers several features to make your shell experience more efficient.

Adjust your font size

Both the Windows Terminal application and the default Windows Console let you adjust your font size.

To temporarily change your font size, hold down the Ctrl key and use the mouse to scroll up or down. In the Windows Terminal application, you can also use the Ctrl+Plus or Ctrl+Minus hotkeys. In the Windows Terminal application, Ctrl+0 resets the font size back to your default.

To change your font size default in the default Windows Console, open the System menu (right-click the title bar at the top left of the console window), select Properties→Font. If you launch Windows PowerShell from the Start menu, it launches with some default modifications to the font and window size. To change your font size default in the Windows Terminal application, add a fontSize setting to any of your terminal profiles:

    {
        "guid": "...",
        "name": "PowerShell (Demos)",
        "fontSize": 18,
        "colorScheme": "Campbell Powershell",
        "source": "Windows.Terminal.PowershellCore"
    },

Adjust other Windows Terminal settings

The Windows Terminal application includes a wealth of configuration settings. A sample of these include:

  • Configuring the list of available shells and applications (such as bash.exe)

  • Color schemes and user interface themes

  • Binding actions to hotkeys

  • Text selection behavior

  • Window transparency

  • Background images

For a full list of these, see the documentation for global settings and general profile settings in Windows Terminal.

Use hotkeys to operate the shell more efficiently

The PowerShell console supports many hotkeys that help make operating the console more efficient, as shown in Table 1-16.

Table 1-16. PowerShell hotkeys
Hotkey Meaning

Press and release the Windows key, and then type pwsh or powershell

Launch PowerShell or Windows PowerShell. The Win+X hotkey also provides a quick way to launch Windows PowerShell.

Up arrow

Scan backward through your command history.

Down arrow

Scan forward through your command history.

Left arrow

Move cursor one character to the left on your command line.

Right arrow

Move cursor one character to the right on your command line. If at the end of the line, inserts a character from the text of your last command at that position.

Ctrl+Left arrow

Move the cursor one word to the left on your command line.

Ctrl+Right arrow

Move the cursor one word to the right on your command line.

Home

Move the cursor to the beginning of the command line.

End

Move the cursor to the end of the command line.

Ctrl+Shift+PgUp, Ctrl+Shift+PgDn

In the Windows Terminal application, scroll through the screen buffer. In the Windows Console, you can use PgUp and PgDn.

Ctrl+Shift+F

In the Windows Terminal application, searches for text in the screen buffer. In the Windows Console, you can use Alt+Space E F.

Alt+Space E K

In the Windows Console, selects text to be copied from the screen buffer.

Ctrl+C

Cancel the current operation. If any text is selected, Ctrl+C copies this text into the clipboard.

Ctrl+V

Paste clipboard contents.

Ctrl+Shift+T

In the Windows Terminal application, opens a new tab. You can also use Ctrl+Shift+1, Ctrl+Shift+2, and similar to open a tab for that numbered profile (such as bash.exe).

Ctrl+Shift+W, Alt+F4

In the Windows Terminal application, close the current tab or entire application. In the Windows Console, you can use Alt+Space C to close the entire application.

Ctrl+Break

In the Windows Console, breaks the PowerShell debugger into the currently running script.

Ctrl+Home

Deletes characters from the beginning of the current command line up to (but not including) the current cursor position.

Ctrl+End

Deletes characters from (and including) the current cursor position to the end of the current command line.

Ctrl+Z, Ctrl+Y

Undo and Redo.

F8

Scan backward through your command history, only displaying matches for commands that match the text you’ve typed so far on the command line.

Ctrl+R

Begins an interactive search backward through your command history based on text you type interactively.

Note

The command-line editing experience offered in PowerShell through the PSReadLine module is far richer than what this table lists. It includes Emacs and Vi key bindings, as well as the ability to define your own—you can see the full default list by typing Get-PSReadLineKeyHandler.

Profiles

PowerShell automatically runs the four scripts listed in Table 1-17 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 1-17. PowerShell profiles
Profile purpose Profile location

Customization of all PowerShell sessions, including PowerShell hosting applications for all users on the system

InstallationDirectory\profile.ps1

Customization of pwsh.exe sessions for all users on the system

InstallationDirectory\Microsoft.PowerShell_profile.ps1

Customization of all PowerShell sessions, including PowerShell hosting applications

<My Documents>\PowerShell\profile.ps1

Typical customization of pwsh.exe sessions

<My Documents>\PowerShell\Microsoft.PowerShell_profile.ps1

In Windows PowerShell, some of these locations will be different.

PowerShell makes editing your profile script simple by defining the automatic variable $profile. By itself, it points to the “current user, pwsh.exe” profile. In addition, the $profile variable defines additional properties that point to the other profile locations:

PS > $profile | Format-List -Force

AllUsersAllHosts       : C:\...Microsoft.PowerShell..\profile.ps1
AllUsersCurrentHost    : C:\...\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts    : D:\Lee\PowerShell\profile.ps1
CurrentUserCurrentHost : D:\...\Microsoft.PowerShell_profile.ps1

To create a new profile, type:

New-Item -Type file -Force $profile

To edit this profile, type:

notepad $profile

Prompts

To customize your prompt, add a prompt function to your profile. This function returns a string. For example:

function prompt
{
    "PS [$env:COMPUTERNAME] >"
}

Tab Completion

You can define a TabExpansion2 function to customize the way that 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:\TabExpansion2

User Input

You can define a PSConsoleHostReadLine function to customize the way that the PowerShell console host (not the Integrated Scripting Environment [ISE]) reads input from the user. This function is responsible for handling all of the user’s keypresses, and finally returning the command that PowerShell should invoke.

Command Resolution

You can intercept PowerShell’s command resolution behavior in three places by assigning a script block to one or all of the PreCommandLookupAction, PostCommandLookupAction, or CommandNotFoundAction properties of $executionContext.SessionState.InvokeCommand.

PowerShell invokes the PreCommandLookupAction after the user types a command name, but before it has tried to resolve the command. It invokes the PostCommandLookupAction once it has resolved a command, but before it executes the command. It invokes the CommandNotFoundAction when a command is not found, but before it generates an error message. Each script block receives two arguments—CommandName and Command​LookupEventArgs:

$executionContext.SessionState.
    InvokeCommand.CommandNotFoundAction = {
        param($CommandName,
    $CommandLookupEventArgs)
        (...)
}

If your script block assigns a script block to the CommandScriptBlock property of the CommandLookupEventArgs or assigns a CommandInfo to the Command property of the CommandLookup​Even⁠tArgs, PowerShell will use that script block or command, respectively. If your script block sets the StopSearch property to true, PowerShell will do no further command resolution.

Get PowerShell Pocket Reference, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.