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.
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
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:
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
Recipe 1.4, “Find a Command to Accomplish a Task”
Recipe 3.4, “Work with .NET Objects”
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.
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
Recipe 16.1, “Enable Scripting Through an Execution Policy.”
“Common Customization Points” in Appendix A
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
Recipe 1.5, “Get Help on a Command”
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
Recipe 1.6, “Program: Search Help for Text”
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.
############################################################################## ## ## 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.
$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.
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.
############################################################################## ## ## 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
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
Recipe 3.4, “Work with .NET Objects”
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.
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
Recipe 3.4, “Work with .NET Objects”
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.
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!
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:
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:
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
Add the text from Example 1-10 to the
Prompt
function in your profile. If you do not yet have aPrompt
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 commandsfunction 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-Contentfilename
.cs | Out-File -Encoding ASCIIfile.txt
Get-ChildItem | Out-File-Width 120 unicodeFile.cs
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
“Capturing Output” in Appendix A
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
Recipe 1.15, “Store the Output of a Command into a File”
“Capturing Output” in Appendix A
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
Recipe 10.3, “Write a Script Block”
Recipe 11.12, “Create a Hashtable or Associative Array”
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 theWriteDebug
() 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 theWriteVerbose
() 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 theWriteProgress
() 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
Recipe 1.20, “Manage the Error Output of Commands”
1.22. Extend Your Shell with Additional Snapins
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:
Obtain the snapin assembly.
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.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 theInstallUtil
utility in the .NET Framework’s installation directory—commonlyC:\WINDOWS\ Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe
.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
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.
<?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.