Chapter 1. The Windows PowerShell Interactive Shell

Introduction

Above all else, the design of Windows PowerShell places priority on its use as an efficient and powerful interactive shell. Even its scripting language plays a critical role in this effort, as it too heavily favors interactive use.

What surprises most people when they first launch PowerShell is its similarity to the command prompt that has long existed as part of Windows. Familiar tools continue to run. Familiar commands continue to run. Even familiar hotkeys are the same. Supporting this familiar user interface, though, is a powerful engine that lets you accomplish once cumbersome administrative and scripting tasks with ease.

This chapter introduces PowerShell from the perspective of its interactive shell.

1.1. Run Programs, Scripts, and Existing Tools

Problem

You rely on a lot of effort invested in your current tools. You have traditional executables, Perl scripts, VBScript, and of course, a legacy build system that has organically grown into a tangled mess of batch files. You want to use PowerShell, but don’t want to give up everything you already have.

Solution

To run a program, script, batch file, or other executable command in the system’s path, enter its filename. For these executable types, the extension is optional:

	Program.exe arguments
	ScriptName.ps1 arguments
	BatchFile.cmd arguments

To run a command that contains a space in its name, enclose its filename in single-quotes (') and precede the command with an ampersand (&), known in PowerShell as the Invoke operator:

	& 'C:\Program Files\Program\Program.exe' arguments

To run a command in the current directory, place .\ in front of its filename:

	.\Program.exe arguments

To run a command with spaces in its name from the current directory, precede it with both an ampersand and .\:

	& '.\Program With Spaces.exe' arguments

Discussion

In this case, the solution is mainly to use your current tools as you always have. The only difference is that you run them in the PowerShell interactive shell, rather than cmd.exe.

The final three tips in the solution merit special attention. They are the features of PowerShell that many new users stumble on when it comes to running programs. The first is running commands that contain spaces. In cmd.exe, the way to run a command that contains spaces is to surround it with quotes:

	"C:\Program Files\Program\Program.exe"

In PowerShell, though, placing text inside quotes is part of a feature that lets you evaluate complex expressions at the prompt, as shown in Example 1-1.

Example 1-1. Evaluating expressions at the PowerShell prompt
PS >1 + 1
2
PS >26 * 1.15
29.9
PS >"Hello" + " World"
Hello World
PS >"Hello World"
Hello World
PS >"C:\Program Files\Program\Program.exe"
C:\Program Files\Program\Program.exe
PS >

So, a program name in quotes is no different from any other string in quotes. It’s just an expression. As shown previously, the way to run a command in a string is to precede that string with the invoke (&) operator. If the command you want to run is a batch file that modifies its environment, see Recipe 1.8, “Program: Retain Changes to Environment Variables Set by a Batch File.”

Tip

By default, PowerShell’s security policies prevent scripts from running. Once you begin writing or using scripts, though, you should configure this policy to something less restrictive. For information on how to configure your execution policy, see Recipe 16.1, “Enable Scripting Through an Execution Policy.”

The second command that new users (and seasoned veterans before coffee!) some-times stumble on is running commands from the current directory. In cmd.exe, the current directory is considered part of the path—the list of directories that Windows searches to find the programname you typed. If you are in the C:\Programs directory, cmd.exe looks in C:\Programs (among other places) for applications to run.

PowerShell, like most Unix shells, requires that you explicitly state your desire to run a program from the current directory. To do that, you use the .\Program.exe syntax, as shown previously. This prevents malicious users on your system from littering your hard drive with evil programs that have names similar to (or the same as) commands you might run while visiting that directory.

To save themselves from having to type the location of commonly used scripts and programs, many users put these utilities along with their PowerShell scripts in a "tools” directory, which they add to their system’s path. If PowerShell can find a script or utility in your system’s path, you do not need to explicitly specify its location.

Tip

Scripts and examples from this book are available at http://www.oreilly.com/catalog/9780596528492.

To learn how to write a PowerShell script, see Recipe 10.1, “Write a Script.

See Also

  • Recipe 1.8, “Program: Retain Changes to Environment Variables Set by a Batch File”

  • Recipe 10.1, “Write a Script

  • Recipe 16.1, “Enable Scripting Through an Execution Policy”

1.2. Run a PowerShell Command

Problem

You want to run a PowerShell command.

Solution

To run a PowerShell command, type its name at the command prompt. For example:

	PS >Get-Process

	Handles  NPM(K)    PM(K)    WS(K)   VM(M)  CPU(s)    Id ProcessName
	-------  ------    -----    -----   -----  ------    -- ----------- 
 	    133       5    11760     7668      46          1112 audiodg
  	    184       5    33248      508      93          1692 avgamsvr
	    143       7    31852      984      97          1788 avgemc

Discussion

The Get-Process command is an example of a native PowerShell command, called a cmdlet. As compared to traditional commands, cmdlets provide significant benefits to both administrators and developers:

  • They share a common and regular command-line syntax.

  • They support rich pipeline scenarios (using the output of one command as the input of another).

  • They produce easily manageable object-based output, rather than error-prone plain text output.

Because the Get-Process cmdlet generates rich object-based output, you can use its output for many process-related tasks.

The Get-Process cmdlet is just one of the many that PowerShell supports. See Recipe 1.4, “Find a Command to Accomplish a Task” to learn techniques for finding additional commands that PowerShell supports.

For more information about working with classes from the .NET Framework, see Recipe 3.4, “Work with .NET Objects.”

See Also

1.3. Customize Your Shell, Profile, and Prompt

Problem

You want to customize PowerShell’s interactive experience with a personalized prompt, aliases, and more.

Solution

When you want to customize aspects of PowerShell, place those customizations in your personal profile script. PowerShell provides easy access to this profile script by storing its location in the $profile variable.

Tip

By default, PowerShell’s security policies prevent scripts (including your profile) from running. Once you begin writing scripts, though, you should configure this policy to something less restrictive. For information on how to configure your execution policy, see Recipe 16.1, “Enable Scripting Through an Execution Policy.”

To create a new profile (and overwrite one if it already exists):

	New-Item -type file -force $profile

To edit your profile:

	notepad $profile

To see your profile file:

	Get-ChildItem $profile

Once you create a profile script, you can add a function called Prompt that returns a string. PowerShell displays the output of this function as your command-line prompt.

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

This example prompt displays your computer name, and look like: PS [LEE-DESK]>

You may also find it helpful to add aliases to your profile. Aliases let you to refer to common commands by a name that you choose. Personal profile scripts let you automatically define aliases, functions, variables, or any other customizations that you might set interactively from the PowerShell prompt. Aliases are among the most common customizations, as they let you refer to PowerShell commands (and your own scripts) by a name that is easier to type.

Tip

If you want to define an alias for a command but also need to modify the parameters to that command, then define a function instead.

For example:

	Set-Alias new New-Object
	Set-Alias iexplore 'C:\Program Files\Internet Explorer\iexplore.exe'

Your changes will become effective once you save your profile and restart Power-Shell. To reload your profile immediately, run the command:

	. $profile

Functions are also very common customizations, with the most popular of those being the Prompt function.

Discussion

Although the Prompt function returns a simple string, you can also use the function for more complex tasks. For example, many users update their console window title (by changing the $host.UI.RawUI.WindowTitle variable) or use the Write-Host cmdlet to output the prompt in color. If your prompt function handles the screen output itself, it still needs to return a string (for example, a single space) to prevent PowerShell from using its default. If you don’t want this extra space to appear in your prompt, add an extra space at the end of your Write-Host command and return the backspace (”'b") character, as shown in Example 1-2.

Example 1-2. An example PowerShell prompt
function Prompt
{
    $id = 1
    $historyItem = Get-History -Count 1
    if($historyItem) 
    {
       $id = $historyItem.Id + 1
    }

    Write-Host -ForegroundColor DarkGray "'n[$(Get-Location)]"
    Write-Host -NoNewLine "PS:$id > "
    $host.UI.RawUI.WindowTitle = "$(Get-Location)"

    "'b"
}

In addition to showing the current location, this prompt also shows the ID for that command in your history. This lets you locate and invoke past commands with relative ease:

	[C:\]
	PS:73 >5 * 5
	25

	[C:\]
	PS:74 >1 + 1
	2

	[C:\]
	PS:75 >Invoke-History 73
	5 * 5
	25

	[C:\]
	PS:76 >

Although the profile referenced by $profile is the one you will almost always want to use, PowerShell actually supports four separate profile scripts. For further details of these scripts (along with other shell customization options), see “Common Customization Points” in Appendix A.

See Also

1.4. Find a Command to Accomplish a Task

Problem

You want to accomplish a task in PowerShell but don’t know the command or cmdlet to accomplish that task.

Solution

Use the Get-Command cmdlet to search for and investigate commands.

To get the summary information about a specific command, specify the command name as an argument:

	Get-Command CommandName

To get the detailed information about a specific command, pipe the output of Get-Command to the Format-List cmdlet:

	Get-Command CommandName | Format-List

To search for all commands with a name that contains text, surround the text with asterisk characters:

	Get-Command *text*

To search for all commands that use the Get verb, supply Get to the -Verb parameter:

	Get-Command -Verb Get

To search for all commands that act on a service, supply Service to the -Noun parameter:

	Get-Command -Noun Service

Discussion

One of the benefits that PowerShell provides administrators is the consistency of its command names. All PowerShell commands (called cmdlets) follow a regular Verb-Noun pattern. For example: Get-Process, Get-EventLog, and Set-Location. The verbs come from a relatively small set of standard verbs (as listed in Appendix D, Standard PowerShell Verbs), and describe what action the cmdlet takes. The nouns are specific to the cmdlet and describe what the cmdlet acts on.

Knowing this philosophy, you can easily learn to work with groups of cmdlets. If you want to start a service on the local machine, the standard verb for that is Start.A good guess would be to first try Start-Service (which in this case would be correct), but typing Get-Command -Verb Start would also be an effective way to see what things you can start. Going the other way, you can see what actions are supported on services by typing Get-Command -Noun Service.

See Recipe 1.5, "Get Help on a Command” for a way to list all commands along with a brief description of what they do.

The Get-Command cmdlet is one of the three commands you will use most commonly as you explore Windows PowerShell. The other two commands are Get-Help and Get-Member.

There is one important point when it comes to looking for a PowerShell command to accomplish a task. Many times, that PowerShell command does not exist, because the task is best accomplished the same way it always was—shutdown.exe to reboot a machine, netstat.exe to list protocol statistics and current TCP/IP network connections, and many more.

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

See Also

1.5. Get Help on a Command

Problem

You want to learn about how a specific command works and how to use it.

Solution

The command that provides help and usage information about a command is called Get-Help. It supports several different views of the help information, depending on your needs.

To get the summary of help information for a specific command, provide the command’s name as an argument to the Get-Help cmdlet. This primarily includes its synopsis, syntax, and detailed description:

	Get-Help CommandName

or

	CommandName -?

To get the detailed help information for a specific command, supply the–Detailed flag to the Get-Help cmdlet. In addition to the summary view, this also includes its parameter descriptions and examples:

	Get-Help CommandName -Detailed

To get the full help information for a specific command, supply the–Full flag to the Get-Help cmdlet. In addition to the detailed view, this also includes its full parameter descriptions and additional notes:

	Get-Help CommandName -Full

To get only the examples for a specific command, supply the–Examples flag to the Get-Help cmdlet:

	Get-Help CommandName -Examples

Discussion

The Get-Help cmdlet is the primary way to interact with the help system in PowerShell. Like the Get-Command cmdlet, the Get-Help cmdlet supports wildcards. If you want to list all commands that match a certain pattern (for example, *process*), you can simply type Get-Help *process*.

Tip

To generate a list of all cmdlets along with a brief synopsis, run the following command:

	Get-Help * | Select-Object Name,Synopsis | Format-Table -Auto

If the pattern matches only a single command, PowerShell displays the help for that command. Although wildcarding is a helpful way to search PowerShell help, see Recipe 1.6, “Program: Search Help for Text” for a script that lets you search the help content for a specified pattern.

The Get-Help cmdlet is one of the three commands you will use most commonly as you explore Windows PowerShell. The other two commands are Get-Command and Get-Member.

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

See Also

1.6. Program: Search Help for Text

Both the Get-Command and Get-Help cmdlets let you search for command names that match a given pattern. However, when you don’t know exactly what portions of a command name you are looking for, you will more often have success searching through the help content for an answer. On Unix systems, this command is called Apropos. Similar functionality does not exist as part of the PowerShell’s help facilities, however.

That doesn’t need to stop us, though, as we can write the functionality ourselves.

To run this program, supply a search string to the Search-Help script (given in Example 1-3). The search string can be either simple text or a regular expression. The script then displays the name and synopsis of all help topics that match. To see the help content for that topic, use the Get-Help cmdlet.

Example 1-3. Search-Help.ps1
##############################################################################
##
## Search-Help.ps1
##
## Search the PowerShell help documentation for a given keyword or regular
## expression.
##
## Example:
##  Search-Help hashtable
##  Search-Help "(datetime|ticks)"
##############################################################################

param($pattern = $(throw "Please specify content to search for"))

$helpNames = $(Get-Help * | Where-Object { $_.Category -ne "Alias" })

foreach($helpTopic in $helpNames)
{
   $content = Get-Help -Full $helpTopic.Name | Out-String
   if($content -match $pattern)
   {
      $helpTopic | Select-Object Name,Synopsis
   }
}

For more information about running scripts, see Recipe 1.1, “Run Programs, Scripts, and Existing Tools.”

See Also

  • Recipe 1.1, “Run Programs, Scripts, and Existing Tools”

1.7. Invoke a PowerShell Script From Outside PowerShell

Problem

You want to invoke a PowerShell script from a batch file, a logon script, scheduled task, or any other non-PowerShell application.

Solution

Launch PowerShell.exe in the following way:

	PowerShell "& 'full path to script' arguments"

For example,

	PowerShell "& 'c:\shared scripts\Get-Report.ps1' Hello World"

Discussion

Supplying a single string argument to PowerShell.exe invokes PowerShell, runs the command as though you had typed it in the interactive shell, and then exits. Since the path to a script often contains spaces, you invoke the script by placing its name between single quotes, and after the & character. If the script name does not contain spaces, you can omit the single quotes and & character. This technique lets you invoke a PowerShell script as the target of a logon script, advanced file association, scheduled task and more.

Tip

If you are the author of the program that needs to run PowerShell scripts or commands, PowerShell lets you call these scripts and commands much more easily than calling its command-line interface. For more information about this approach, see Recipe 15.13, “Add PowerShell Scripting to Your Own Program.”

If the command becomes much more complex than a simple script call, special characters in the application calling PowerShell (such as cmd.exe) might interfere with the command you want to send to PowerShell. For this situation, PowerShell supports an EncodedCommand parameter: a Base64 encoded representation of the Unicode string you want to run. Example 1-4 demonstrates how to convert a string containing PowerShell commands to a Base64 encoded form.

Example 1-4. Converting PowerShell commands into a Base64 encoded form
$commands = '1..10 | % { "PowerShell Rocks" }'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($commands)
$encodedString = [Convert]::ToBase64String($bytes)

Once you have the encoded string, you can use it as the value of the EncodedCommand parameter, as shown in Example 1-5.

Example 1-5. Launching PowerShell with an encoded command from cmd.exe
Microsoft Windows [Version 6.0.6000]
Copyright (c) 2006 Microsoft Corporation. All rights reserved.

C:\Users\Lee>PowerShell -EncodedCommand MQAuAC4AMQAwACAAfAAgACUAIAB7ACAAIgBQAG8A↵
dwBlAHIAUwBoAGUAbABsACAAUgBvAGMAawBzACIAIAB9AA==
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks
PowerShell Rocks

For more information about how to invoke PowerShell scripts, see Recipe 1.1, “Run Programs, Scripts, and Existing Tools.”

See Also

  • Recipe 1.1, “Run Programs, Scripts, and Existing Tools”

  • Recipe 15.13, “Add PowerShell Scripting to Your Own Program”

1.8. Program: Retain Changes to Environment Variables Set by a Batch File

When a batch file modifies an environment variable, cmd.exe retains this change even after the script exits. This often causes problems, as one batch file can accidentally pollute the environment of another. That said, batch file authors sometimes intentionally change the global environment to customize the path and other aspects of the environment to suit a specific task.

However, environment variables are private details of a process and disappear when that process exits. This makes the environment customization scripts mentioned above stop working when you run them from PowerShell—just as they fail to work when you run them from another cmd.exe (for example, cmd.exe /c MyScript.cmd).

The script in Example 1-6 lets you run batch files that modify the environment and retain their changes even after cmd.exe exits. It accomplishes this by storing the environment variables in a text file once the batch file completes, and then setting all those environment variables again in your PowerShell session.

To run this script, type Invoke-CmdScript Scriptname.cmd or Invoke-CmdScript Scriptname.bat—whichever extension the batch files uses.

Tip

If this is the first time you’ve run a script in PowerShell, you will need to configure your Execution Policy. For more information about selecting an execution policy, see Recipe 16.1, “Enable Scripting Through an Execution Policy.”

Notice that this script uses the full names for cmdlets: Get-Content, Foreach-Object, Set-Content, and Remove-Item. This makes the script readable and is ideal for scripts that somebody else will read. It is by no means required, though. For quick scripts and interactive use, shorter aliases (such as gc, %, sc, and ri) can make you more productive.

Example 1-6. Invoke-CmdScript.ps1
##############################################################################
##
## Invoke-CmdScript.ps1
##
## Invoke the specified batch file (and parameters), but also propagate any
## environment variable changes back to the PowerShell environment that
## called it.
##
## i.e., for an already existing 'foo-that-sets-the-FOO-env-variable.cmd': 
##
## PS > type foo-that-sets-the-FOO-env-variable.cmd
## @set FOO=%*
## echo FOO set to %FOO%.
##
## PS > $env:FOO
##
## PS > Invoke-CmdScript "foo-that-sets-the-FOO-env-variable.cmd" Test 
##
## C:\Temp>echo FOO set to Test. 
## FOO set to Test.
##
## PS > $env:FOO 
## Test 
##
##############################################################################

param([string] $script, [string] $parameters)

$tempFile = [IO.Path]::GetTempFileName()

## Store the output of cmd.exe. We also ask cmd.exe to output
## the environment table after the batch file completes 
cmd /c " '"$script'" $parameters && set > '"$tempFile'" "

## Go through the environment variables in the temp file.
## For each of them, set the variable in our local environment.
Get-Content $tempFile | Foreach-Object {
    if($_ -match "^(.*?)=(.*)$")
    {
        Set-Content "env:\$($matches[1])" $matches[2]
    }
}

Remove-Item $tempFile

For more information about running scripts, see Recipe 1.1, “Run Programs, Scripts, and Existing Tools.”

See Also

  • Recipe 1.1, “Run Programs, Scripts, and Existing Tools”

  • Recipe 16.1, “Enable Scripting Through an Execution Policy”

1.9. Get the System Date and Time

Problem

You want to get the system date.

Solution

To get the system date, run the command Get-Date.

Discussion

The Get-Date command generates rich object-based output, so you can use its result for many date-related tasks. For example, to determine the current day of the week:

	PS >$date = Get-Date
	PS >$date.DayOfWeek
	Sunday

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

For more information about working with classes from the .NET Framework, see Recipe 3.4, “Work with .NET Objects.”

See Also

1.10. Determine the Status of the Last Command

Problem

You want to get status information about the last command you executed, such as whether it succeeded.

Solution

Use one of the two variables PowerShell provides to determine the status of the last command you executed: the $lastExitCode variable and the $? variable.

$lastExitCode

A number that represents the exit code/error level of the last script or application that exited

$? (pronounced "dollar hook")

A Boolean value that represents the success or failure of the last command

Discussion

The $lastExitCode PowerShell variable is similar to the %errorlevel% variable in DOS. It holds the exit code of the last application to exit. This lets you continue to interact with traditional executables (such as ping, findstr, and choice) that use exit codes as a primary communication mechanism. PowerShell also extends the meaning of this variable to include the exit codes of scripts, which can set their status using the exit statement. Example 1-7 demonstrates this interaction.

Example 1-7. Interacting with the $lastExitCode and $? variables
PS >ping localhost

Pinging MyComputer [127.0.0.1] with 32 bytes of data:

Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milliseconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
PS >$?
True
PS >$lastExitCode

0
PS >ping missing-host
Ping request could not find host missing-host. Please check the name and try again.
PS >$?
False
PS >$lastExitCode
1

The $? variable describes the exit status of the last application in a more general manner. PowerShell sets this variable to False on error conditions such as when:

  • An application exits with a non-zero exit code.

  • A cmdlet or script writes anything to its error stream.

  • A cmdlet or script encounters a terminating error or exception.

For commands that do not indicate an error condition, PowerShell sets the $? variable to True.

1.11. Measure the Duration of a Command

Problem

You want to know how long a command takes to execute.

Solution

To measure the duration of a command, use the Measure-Command cmdlet:

	PS >Measure-Command { Start-Sleep -Milliseconds 337 }

	Days              : 0
	Hours             : 0
	Minutes           : 0
	Seconds           : 0
	Milliseconds      : 339
	Ticks             : 3392297
	TotalDays         : 3.92626967592593E-06
	TotalHours        : 9.42304722222222E-05
	TotalMinutes      : 0.00565382833333333
	TotalSeconds      : 0.3392297
	TotalMilliseconds : 339.2297

Discussion

In interactive use, it is common to want to measure the duration of a command. An example of this might be running a performance benchmark on an application you’ve developed. The Measure-Command cmdlet makes this easy to do. Because the command generates rich object-based output, you can use its output for many date-related tasks. See Recipe 3.4, “Work with .NET Objects,” for more information.

For more information about the Measure-Command cmdlet, type Get-Help Measure-Command.

See Also

1.12. Customize the Shell to Improve Your Productivity

Problem

You want to use the PowerShell console more efficiently for copying, pasting, history management, and scrolling.

Solution

Run the commands shown in Example 1-8 to permanently customize your Power-Shell console windows and make many tasks easier.

Example 1-8. Set-ConsoleProperties.ps1
Push-Location
Set-Location HKCU:\Console
New-Item '.\%SystemRoot%_system32_WindowsPowerShell_v1.0_powershell.exe'
Set-Location '.\%SystemRoot%_system32_WindowsPowerShell_v1.0_powershell.exe'

New-ItemProperty . ColorTable00 -type DWORD -value 0x00562401
New-ItemProperty . ColorTable07 -type DWORD -value 0x00f0edee
New-ItemProperty . FaceName -type STRING -value "Lucida Console"
New-ItemProperty . FontFamily -type DWORD -value 0x00000036
New-ItemProperty . FontSize -type DWORD -value 0x000c0000
New-ItemProperty . FontWeight -type DWORD -value 0x00000190
New-ItemProperty . HistoryNoDup -type DWORD -value 0x00000000
New-ItemProperty . QuickEdit -type DWORD -value 0x00000001
New-ItemProperty . ScreenBufferSize -type DWORD -value 0x0bb80078
New-ItemProperty . WindowSize -type DWORD -value 0x00320078
Pop-Location

These commands customize the console color, font, history storage properties, QuickEdit mode, buffer size, and window size.

With these changes in place, you can also improve your productivity by learning some of the hotkeys for common tasks, as listed in Table 1-1. PowerShell uses the same input facilities as cmd.exe, and so brings with it all the input features that you are already familiar with—and some that you aren’t!

Table 1-1. Partial list of Windows PowerShell hotkeys

Hotkey

Meaning

Up arrow

Scan backward through your command history.

Down arrow

Scan forward through your command history.

PgUp

Display the first command in your command history.

PgDown

Display the last command in 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.

Home

Move the cursor to the beginning of the command line.

End

Move the cursor to the end of the command line.

Control + Left arrow

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

Control + Right arrow

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

Discussion

When you launch PowerShell from the link on your Windows Start menu, it customizes several aspects of the console window:

  • Foreground and background color, to make the console more visually appealing

  • QuickEdit mode, to make copying and pasting with the mouse easier

  • Buffer size, to make PowerShell retain the output of more commands in your console history

By default, these customizations do not apply when you run PowerShell from the Start → Run dialog. The commands given in the solution section improve the experience by applying these changes to all PowerShell windows that you open.

The hotkeys do, however, apply to all PowerShell windows (and any other application that uses Windows’ cooked input mode). The most common are given in the in the solution section, but “Common Customization Points” in Appendix A provides the full list.

See Also

“Common Customization Points” in Appendix A

1.13. Program: Learn Aliases for Common Commands

In interactive use, full cmdlet names (such as Get-ChildItem) are cumbersome and slow to type. Although aliases are much more efficient, it takes awhile to discover them. To learn aliases more easily, you can modify your prompt to remind you of the shorter version of any aliased commands that you use.

This involves two steps:

  1. Add the program,Get-AliasSuggestion.ps1, shown in Example 1-9, to your tools directory or other directory.

    Example 1-9. Get-AliasSuggestion.ps1
    ##############################################################################
    ##
    ## Get-AliasSuggestion.ps1
    ##
    ## Get an alias suggestion from the full text of the last command
    ##
    ## ie:
    ##
    ## PS > Get-AliasSuggestion Remove-ItemProperty
    ## Suggestion: An alias for Remove-ItemProperty is rp
    ##
    ############################################################################## 
    
    param($lastCommand)
    
    $helpMatches = @()
    
    ## Get the alias suggestions
    foreach($alias in Get-Alias)
    {
        if($lastCommand -match ("\b" +
            [System.Text.RegularExpressions.Regex]::Escape($alias.Definition) + "\b"))
        {
            $helpMatches += "Suggestion: An alias for $($alias.Definition) is $($alias.Name)" 
        }
    }
    
    $helpMatches
  2. Add the text from Example 1-10 to the Prompt function in your profile. If you do not yet have a Prompt function, see Recipe 1.3, “Customize Your Shell, Profile, and Prompt” to learn how to add one. If you already have a prompt function, you only need to add the content from inside the prompt function of Example 1-10.

    Example 1-10. A useful prompt to teach you aliases for common commands
        function Prompt
        {
        ## Get the last item from the history
        $historyItem = Get-History -Count 1
    
        ## If there were any history items
        if($historyItem)
        {
            ## Get the training suggestion for that item
            $suggestions = @(Get-AliasSuggestion $historyItem.CommandLine)
            ## If there were any suggestions
            if($suggestions)
            {
                ## For each suggestion, write it to the screen
                foreach($aliasSuggestion in $suggestions)
                {
                    Write-Host "$aliasSuggestion"
                }
                Write-Host "" 
    
            }
        }
    
        ## Rest of prompt goes here
        "PS [$env:COMPUTERNAME] >"
    }

For more information about running scripts, see Recipe 1.1, “Run Programs, Scripts, and Existing Tools.”

See Also

  • Recipe 1.1, “Run Programs, Scripts, and Existing Tools”

  • Recipe 1.3, “Customize Your Shell, Profile, and Prompt”

1.14. Access and Manage Your Console History

Problem

After working in the shell for a while, you want to invoke commands from your history, view your command history, and save your command history.

Solution

The shortcuts given in Recipe 1.12, “Customize the Shell to Improve Your Productivity” let you manage your history, but PowerShell offers several features to help you work with your console in even more detail.

To get the most recent commands from your session, use the Get-History cmdlet:

	Get-History

To rerun a specific command from your session history, provide its Id to the Invoke-History cmdlet:

	Invoke-History Id

To increase (or limit) the number of commands stored in your session history, assign a new value to the $MaximumHistoryCount variable:

	$MaximumHistoryCount = Count

To save your command history to a file, pipe the output of Get-History to the Export-CliXml cmdlet:

	Get-History | Export-CliXml Filename

To add a previously saved command history to your current session history, call the Import-CliXml cmdlet and then pipe that output to the Add-History cmdlet:

	Import-CliXml Filename | Add-History

Discussion

Unlike the console history hotkeys discussed in Recipe 1.12, “Customize the Shell to Improve Your Productivity” the Get-History cmdlet produces rich objects that represent information about items in your history. Each object contains that item’s ID, command line, start of execution time, and end of execution time.

Once you know the ID of a history item(as shown in the output of Get-History), you can pass it to Invoke-History to execute that command again. The example prompt function shown in Recipe 1.3, “Customize Your Shell, Profile, and Prompt” makes working with prior history items easy—as the prompt for each command includes the history ID that will represent it.

The IDs provided by the Get-History cmdlet differ from the IDs given by the Windows console common history hotkeys (such as F7), because their history management techniques differ.

By default, PowerShell stores only the last 64 entries of your command history. If you want to raise or lower this amount, set the $MaximumHistoryCount variable to the size you desire. To make this change permanent, set the variable in your PowerShell profile script. To clear your history, either restart the shell, or temporarily set the $MaximumHistoryCount variable to 1.

See Also

  • Recipe 1.3, “Customize Your Shell, Profile, and Prompt”

  • Recipe 1.12, “Customize the Shell to Improve Your Productivity”

1.15. Store the Output of a Command into a File

Problem

You want to redirect the output of a pipeline into a file.

Solution

To redirect the output of a command into a file, use either the Out-File cmdlet or one of the redirection operators.

Out-File:

	Get-ChildItem | Out-File unicodeFile.txt
	Get-Content filename.cs | Out-File -Encoding ASCII file.txt
	Get-ChildItem | Out-File-Width 120 unicodeFile.cs

Redirection operators:

	Get-ChildItem > files.txt
	Get-ChildItem 2> errors.txt

Discussion

The Out-File cmdlet and redirection operators share a lot in common—and for the most part, you can use either. The redirection operators are unique because they give the greatest amount of control over redirecting individual streams. The Out-File cmdlet is unique primarily because it lets you easily configure the formatting width and encoding.

The default formatting width and the default output encoding are two aspects of output redirection that can sometimes cause difficulty.

The default formatting width sometimes causes problems because redirecting PowerShell-formatted output into a file is designed to mimic what you see on the screen. If your screen is 80 characters wide, the file will be 80 characters wide as well. Examples of PowerShell-formatted output include directory listings (that are implicitly for-matted as a table) as well as any commands that you explicitly format using one of the Format-*set of cmdlets. If this causes problems, you can customize the width of the file with the—Width parameter on the Out-File cmdlet.

The default output encoding sometimes causes unexpected results because PowerShell creates all files using the UTF-16 Unicode encoding by default. This allows PowerShell to fully support the entire range of international characters, cmdlets, and output. Although this is a great improvement to traditional shells, it may cause an unwanted surprise when running large search and replace operations on ASCII source code files, for example. To force PowerShell to send its output to a file in the ASCII encoding, use the—Encoding parameter on the Out-File cmdlet.

For more information about the Out-File cmdlet, type Get-Help Out-File. For a full list of supported redirection operators, see “Capturing Output” in Appendix A.

See Also

1.16. Add Information to the End of a File

Problem

You want to redirect the output of a pipeline into a file but add the information to the end of that file.

Solution

To redirect the output of a command into a file, use either the -Append parameter of the Out-File cmdlet, or one of the appending redirection operators as described in “Capturing Output” in Appendix A. Both support options to append text to the end of a file.

Out-File:

	Get-ChildItem | Out-File -Append files.txt

Redirection operators:

	Get-ChildItem >> files.txt

Discussion

The Out-File cmdlet and redirection operators share a lot in common—and for the most part, you can use either. See the discussion in Recipe 1.15, “Store the Output of a Command into a File” for a more detailed comparison of the two approaches, including reasons that you would pick one over the other.

See Also

1.17. Record a Transcript of Your Shell Session

Problem

You want to record a log or transcript of your shell session.

Solution

To record a transcript of your shell session, run the command Start-Transcript Path. Path is optional and defaults to a filename based on the current system time. By default, PowerShell places this file in the My Documents directory. To stop recording the transcript of your shell system, run the command Stop-Transcript.

Discussion

Although the Get-History cmdlet is helpful, it does not record the output produced during your PowerShell session. To accomplish that, use the Start-Transcript cmdlet. In addition to the Path parameter described previously, the Start-Transcript cmdlet also supports parameters that let you control how PowerShell interacts with the output file.

1.18. Display the Properties of an Item As a List

Problem

You have an item (for example, an error record, directory item, or .NET object), and you want to display detailed information about that object in a list format.

Solution

To display detailed information about an item, pass that item to the Format-List cmdlet. For example, to display an error in list format, type the commands:

	$currentError = $error[0]
	$currentError | Format-List -Force

Discussion

The Format-List cmdlet is one of the three PowerShell formatting cmdlets. These cmdlets include Format-Table, Format-List, and Format-Wide. The Format-List cmdlet takes input and displays information about that input as a list. By default, PowerShell takes the list of properties to display from the *.format.ps1xml files in PowerShell’s installation directory. To display all properties of the item, type Format-List *. Sometimes, you might type Format-List * but still not get a list of the item’s properties. This happens when the item is defined in the *.format.ps1xml files, but does not define anything to be displayed for the list command. In that case, type Format-List-Force.

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

1.19. Display the Properties of an Item As a Table

Problem

You have a set of items (for example, error records, directory items, or .NET objects), and you want to display summary information about them in a table format.

Solution

To display summary information about a set of items, pass those items to the Format-Table cmdlet. This is the default type of formatting for sets of items in PowerShell and provides several useful features.

To use PowerShell’s default formatting, pipe the output of a cmdlet (such as the Get-Process cmdlet) to the Format-Table cmdlet:

	Get-Process | Format-Table

To display specific properties (such as Name and WorkingSet,) in the table formatting, supply those property names as parameters to the Format-Table cmdlet:

	Get-Process | Format-Table Name,WS

To instruct PowerShell to format the table in the most readable manner, supply the–Auto flag to the Format-Table cmdlet. PowerShell defines “WS” as an alias of the WorkingSet for processes:

	Get-Process | Format-Table Name,WS -Auto

To define a custom column definition (such as a process’s Working Setin mega-bytes), supply a custom formatting expression to the Format-Table cmdlet:

	$fields = "Name",@{Label = "WS (MB)"; Expression = {$_.WS / 1mb}; Align = "Right"} 
	Get-Process | Format-Table $fields -Auto

Discussion

The Format-Table cmdlet is one of the three PowerShell formatting cmdlets. These cmdlets include Format-Table, Format-List, and Format-Wide. The Format-Table cmdlet takes input and displays information about that input as a table. By default, PowerShell takes the list of properties to display from the *.format.ps1xml files in PowerShell’s installation directory. You can display all properties of the items if you type Format-Table *, although this is rarely a useful view.

The -Auto parameter to Format-Table is a helpful way to automatically format the table to use screen space as efficiently as possible. It does come at a cost, however. To figure out the best table layout, PowerShell needs to examine each item in the incoming set of items. For small sets of items, this doesn’t make much difference, but for large sets (such as a recursive directory listing) it does. Without the -Auto parameter, the Format-Table cmdlet can display items as soon as it receives them. With the -Auto flag, the cmdlet can only display results after it receives all the input.

Perhaps the most interesting feature of the Format-Table cmdlet is illustrated by the last example—the ability to define completely custom table columns. You define a custom table column similarly to the way that you define a custom column list. Rather than specify an existing property of the items, you provide a hashtable. That hashtable includes up to three keys: the column’s label, a formatting expression, and alignment. The Format-Table cmdlet shows the label as the column header and uses your expression to generate data for that column. The label must be a string, the expression must be a script block, and the alignment must be either "Left“, "Center“,or "Right“. In the expression script block, the $_ variable represents the current item being formatted.

The expression shown in the last example takes the working set of the current item and divides it by 1 megabyte (1 MB).

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

For more information about hashtables, see Recipe 11.12, “Create a Hashtable or Associative Array.”

For more information about script blocks, see Recipe 10.3, “Write a Script Block.”

See Also

1.20. Manage the Error Output of Commands

Problem

You want to display detailed information about errors that come from commands.

Solution

To list all errors (up to $MaximumErrorCount) that have occurred in this session, access the $error array:

	$error

To list the last error that occurred in this session, access the first element in the $error array:

	$error[0]

To list detailed information about an error, pipe the error into the Format-List cmdlet with the -Force parameter:

	$currentError = $error[0]
	$currentError | Format-List -Force

To list detailed information about the command that caused an error, access its InvocationInfo property:

	$currentError = $error[0]
	$currentError.InvocationInfo

To display errors in a more succinct category-based view, change the $errorView variable to "CategoryView“:

	$errorView = "CategoryView"

To clear the list of errors collected by PowerShell so far, call the Clear() method on the $error variable:

	$error.Clear()

Discussion

Errors are a simple fact of life in the administrative world. Not all errors mean disaster, though. Because of this, PowerShell separates errors into two categories: nonterminating and terminating.

Nonterminating errors are the most common type of error. They indicate that the cmdlet, script, function, or pipeline encountered an error that it was able to recover from or was able to continue past. An example of a nonterminating error comes from the Copy-Item cmdlet. If it fails to copy a file from one location to another, it can still proceed with the rest of the files specified.

A terminating error, on the other hand, indicates a deeper, more fundamental error in the operation. An example of this can again come from the Copy-Item cmdlet when you specify invalid command-line parameters.

For more information on how to handle both nonterminating and terminating errors, see Chapter 13, Tracing and Error Management.

See Also

Chapter 13, Tracing and Error Management

1.21. Configure Debug, Verbose, and Progress Output

Problem

You want to manage the detailed debug, verbose, and progress output generated by cmdlets and scripts.

Solution

To enable debug output for scripts and cmdlets that generate it:

	$debugPreference = "Continue"
	Start-DebugCommand

To enable verbose mode for a cmdlet that checks for the -Verbose parameter:

	Copy-Item c:\temp\*.txt c:\temp\backup\ -Verbose

To disable progress output from a script or cmdlet that generates it:

	$progressPreference = "SilentlyContinue"
	Get-Progress.ps1

Discussion

In addition to error output (as described in Recipe 1.20, “Manage the Error Output of Commands”), many scripts and cmdlets generate several other types of output. This includes:

Debug output

Helps you diagnose problems that may arise and can provide a view into the inner workings of a command. You can use the Write-Debug cmdlet to produce this type of output in a script or the WriteDebug() method to produce this type of output in a cmdlet. PowerShell displays this output in yellow, unless you customize it through the $host.PrivateData.Debug* color configuration variables.

Verbose output

Helps you monitor the actions of commands at a finer level than the default. You can use the Write-Verbose cmdlet to produce this type of output in a script or the WriteVerbose() method to produce this type of output in a cmdlet. PowerShell displays this output in yellow, unless you customize it through the $host.PrivateData.Verbose* color configuration variables.

Progress output

Helps you monitor the status of long-running commands. You can use the Write-Progress cmdlet to produce this type of output in a script or the WriteProgress() method to produce this type of output in a cmdlet. PowerShell displays this output in yellow, unless you customize it through the $host.PrivateData.Progress* color configuration variables.

Some cmdlets generate verbose and debug output only if you specify the -Verbose and -Debug parameters, respectively.

To configure the debug, verbose, and progress output of a script or cmdlet, modify the $debugPreference, $verbosePreference, and $progressPreference shell variables. These variables can accept the following values:

SilentlyContinue

Do not display this output.

Stop

Treat this output as an error.

Continue

Display this output.

Inquire

Display a continuation prompt for this output.

See Also

1.22. Extend Your Shell with Additional Snapins

Problem

You want to use PowerShell cmdlets and providers written by a third party.

Solution

In PowerShell, extensions that contain additional cmdlets and providers are called snapins. The author might distribute them with an automated installer but can also distribute them as a standalone PowerShell assembly. PowerShell identifies each snapin by the filename of its assembly and by the snapin name that its author provides.

To use a snapin:

  1. Obtain the snapin assembly.

  2. Copy it to a secure location on your computer. Since snapins are equivalent to executable programs, pick a location (such as the Program Files directory) that provides users read access but not write access.

  3. Register the snapin. From the directory that contains the snapin assembly, run InstallUtil SnapinFilename.dll. This command lets all users on the computer load and run commands defined by the snapin. You can find the InstallUtil utility in the .NET Framework’s installation directory—commonly C:\WINDOWS\ Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe.

  4. Add the snapin. At a PowerShell prompt (or in your profile file), run the command Add-PsSnapin SnapinIdentifier. To see all available snapin identifiers, review the names listed in the output of the command:

    	Get-PsSnapin -Registered
  5. Use the cmdlets and providers contained in that snapin.

To remove the snapin registration from your system, type InstallUtil /u SnapinFilename.dll. Once uninstalled, you may delete the files associated with the snapin.

Discussion

For interactive use (or in a profile), the Add-PsSnapin cmdlet is the most common way to load an individual snapin. To load a preconfigured list of snapins, though, the following section Recipe 1.23, “Use Console Files to Load and Save Sets of Snapins” offers another option.

One popular source of additional snapins is the PowerShell Community Extensions project, located at http://www.codeplex.com/PowerShellCX.

See Also

  • Recipe 1.23, “Use Console Files to Load and Save Sets of Snapins”

1.23. Use Console Files to Load and Save Sets of Snapins

Problem

You want to load PowerShell with a set of additional snapins, but do not want to modify your (or the user’s) profile.

Solution

Once you register a snapin on your system, you can add its snapin identifier to a PowerShell console file to load it. When you specify that file as the -PsConsoleFile parameter of PowerShell.exe, PowerShell loads all snapins defined by the console file into the new session.

Save the list of currently loaded snapins to a console file:

	Export-Console Filename.psc1

Load PowerShell with the set of snapins defined in the file Filename.psc1:

	PowerShell -PsConsoleFile Filename.psc1

Discussion

PowerShell console files are simple XML files that list the identifiers of already-installed snapins to load. A typical console file looks like Example 1-11.

Example 1-11. A typical PowerShell console file
<?xml version="1.0" encoding="utf-8"?>
<PSConsoleFile ConsoleSchemaVersion="1.0">
  <PSVersion>1.0</PSVersion>
  <PSSnapIns>
    <PSSnapIn Name="CustomSnapin" />
    <PSSnapIn Name="SecondSnapin" />
  </PSSnapIns>
</PSConsoleFile>

Console files should be saved with the file extension .psc1.

Although it is common to load the console file with PowerShell’s command-line options (in scripts and automated tasks), you can also double-click on the console file to load it interactively.

For more information on how to manage snapins, see Recipe 1.22, “Extend Your Shell with Additional Snapins”.

See Also

  • Recipe 1.22, “Extend Your Shell with Additional Snapins”

Get Windows PowerShell Cookbook 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.