Customizing Windows PowerShell's Internal Functions

You can redefine, change through aliasing, or delete Windows PowerShell's internal functions to create the best work environment for your needs. Add your customizations to a profile script to make them persistent.

Several PowerShell commands are actually functions predefined by an internal script that runs when PowerShell starts up. However, you can freely redefine these functions to suit your personal preferences. I'll demonstrate the techniques—redefining, aliasing, and simple deletion—primarily using PowerShell's prompt and more functions; in the process, you'll see some of the situations where redefining functions makes sense. Because the functions we're modifying are automatically created by PowerShell at startup, the changes are only temporary. They'll be reset to the default each time you start PowerShell. So, as a final topic, I'll discuss making the changes happen automatically at PowerShell startup using a PowerShell profile script.Redefining PowerShell's Prompt FunctionPowerShell's prompt is a function invoked each time a command finishes executing. The returned value from the function is used for the next onscreen prompt. The default prompt displays the current PowerShell location. In PowerShell, location is analogous to the working directory for a Windows process, but it isn't precisely the same; your current location might be a registry hive or certificate store. In any case, including the location often makes the prompt extremely long, cluttering the screen with information that I usually don't find valuable.

We can inspect the contents of the prompt function by getting its syntax information (technically, the function's definition) by entering the following command:

(Get-Command prompt).Definition

Figure 1 shows the results you'll see when using PowerShell 1.0. This is the entire internal content of the function named prompt. The location information is inserted by the $(Get-Location) element. There's also a test of the $nestedpromptlevel variable, which I won't discuss; the $nestedpromptlevel test is used to give you a special prompt (>>) when you enter a single statement on multiple lines. To create a new prompt function that removes the location data, you can simply enter the following at a command prompt (or execute it automatically in your PowerShell profile):

However, you could make some different changes here. What if you don't want the location information cluttering the screen, but would like it to be displayed somewhere else—such as the PowerShell window's title bar?

It turns out that the host window's title bar is accessible via PowerShell's automatic $host variable. The window properties are buried deep within the $host object (the reasons are too long to go into and no more fun than knowing how sausages are made), but you can find the properties if you check $host.UI.RawUI with Get-Member:

$host.UI.RawUI | get-member

As Figure 2 shows, $host.UI.RawUI has a WindowTitle property, which you can change. To set the window title to the current PowerShell location, you can use the Get-Location cmdlet:

$host.UI.RawUI.WindowTitle ` = Get-Location

For our purposes, we want to set the window title property to the current location each time PowerShell calls the prompt function, so we insert the line into our prompt function:

You'll see that the PowerShell window now shows your current location.

Hiding PowerShell Functions with an AliasPowerShell provides console output paging through the more function. This function is very bare-bones. All it does is display a screen full of console output, then moves forward one screen every time you hit the Space key and moves forward one line every time you hit the Enter key. You can give the more function a list of files to display instead of giving it input text, but you can't move to the next file in the provided list as you can with the F key extended feature of more.com, which is cmd.exe's more command executable. More.com also provides some other special abilities: It can clear the current screen before starting paging (use /C) and can compress multiple blank lines into a single line (use /S). Enter more.com /? at a command prompt to see more.com's functionality.

If you want to use more.com instead of the more function, you could write a replacement function that explicitly refers to more.com, but wrapping it up could be a headache if you want it to handle input as well as filenames provided on the command line. Instead, you can set up an alias to tell PowerShell that more always means more.com by entering the following command:

Set-Alias more more.com

PowerShell always resolves aliases before other command types, so it will see that more means more.com and use more.com whenever more is called.

If you've had experience with UNIX command shells, you might prefer to use the console pager named less. A Windows version of the less pager is available from the Less Web page (http://www.greenwoodsoftware.com/less). Even if you haven't used other console pagers, you might want to investigate less. You can find a quick summary of what it can do on the Less FAQ page. If you're used to using the less pager, you can use the Set-Alias cmdlet to set more's alias to less:

Set-Alias more less

This technique is often used on UNIX systems when changing the default pager, and there's a reason for it (beyond the internal UNIX world joke about "more is less"). When you use a shell a lot, you develop "finger memory" for specific actions, which become almost reflexes. One of those reflexes usually involves the pager you use. If you have less installed on a system you use regularly and it isn't available when you're working somewhere else, you'll find yourself continually typing "less" and receiving errors, then having to rerun commands. If you instead always call your pager more, the only problem you'll have is that there will be different paging controls. Although I'm using less to demonstrate hiding a function with an alias, you could simply place less in a directory in your search path, then invoke it as less, leaving the more pager alone.

Deleting PowerShell FunctionsThe final way to modify PowerShell functions—and it's actually the simplest—is to remove any you don't want. PowerShell functions are exposed through a drive named function. (Note that you actually could have other function drives, which is why I say this is a drive named function rather than the function drive. If you're using a standard PowerShell installation, however, you can safely assume that there is only one function drive and that it's named function.) You can list all of the functions using the directory-listing cmdlet, Get-ChildItem:

Get-ChildItem function:\

You use the Remove-Item cmdlet to delete functions. For example, we can also get more.com as the default pager if we just delete the more function with the following command:

Remove-Item function:\more

One tweak I occasionally use in PowerShell is removing all of the drive-change functions. There are functions A:, B:, and so on to Z: that are just convenient compatibility hacks designed to mimic the ability to change a drive that you get in cmd.exe by typing a drive name followed by a colon. So if you type Z:, your PowerShell location changes to the Z drive if you have one (and gives you an error if you don't).

I typically delete the drive-change functions because I don't use them. I have many custom functions, and it's much easier to view them quickly when unused functions are removed. PowerShell 1.0 has 34 built-in functions; with the drive-change functions removed, there are only 8. Remove-Item takes wildcard sequences in names of items it's going to remove, so I can get rid of the drive-change functions easily in one short line:

Remove-Item function:\\[a-z\]:

The function:\ portion of this command is just the base path of all functions. The \[a-z\] is a PowerShell wildcard expression meaning "any single character from a through z." The final colon (:) is here because it's actually part of the function name.

After removing functions, you can once again examine the currently defined functions and see how they've changed by using

Get-ChildItem function:\

Making Function Changes PersistentIf you want to customize your environment but don't want to type in your customizations each time you run PowerShell, here's how to make the process automatic. PowerShell always runs the internal script defining some functions when it starts up. After running its own script, it looks to see if you have a personal profile script. PowerShell checks your documents folder for a subfolder named WindowsPowerShell. If the folder is there, PowerShell looks for a script named Microsoft.PowerShell_profile.ps1, and runs the script if it exists. If you include the customizations you want in this profile script, they'll be taken care of by the time you get a PowerShell prompt. For more detailed information on PowerShell's profile scripts, see "What You Need to Know to Start Using PowerShell's Personal Profile Scripts," http://www.scriptingprovip.com/articles/articleid/97669/97669.html. I also suggest reading Microsoft's Windows PowerShell Profiles documentation (http://msdn2.microsoft.com/en-us/library/bb613488.aspx).

If you're worried about redefining internal functions, you should be aware that this is the reason they're exposed as functions. Paging, prompt configuration, and other functionality such as tab expansion are controlled via functions because these are features end users typically need to modify to suit personal tastes and situations. Tailoring PowerShell to suit your work habits can make it a much more useful tool. If you make changes and later find you don’t like them, you can delete the changes or rename the profile script and get back the original PowerShell functions.

John Savill's Hyper-V Master Class

Join John Savill for 12 hours of comprehensive Hyper-V training. This master-level online training course will explore all the key aspects of a Hyper-V based virtualization environment covering both current capabilities in Windows Server 2012 R2 and looking at the future with Windows Server vNext.