Windows PowerShellThe Power of Profiles

Don Jones

Shells, Hosts, and Profiles
Using Your Profile?
Making a Custom Console
More Profile Tricks
Profile Beware!

If you read this column regularly, you know by now that Windows PowerShell supports a system of profiles. These are essentially shell scripts, with a .ps1 file name extension, that execute automatically when the shell runs. These provide a great way to define custom aliases, for example. You can have it so that each time the shell runs, the profile automatically defines your aliases, making them available anytime you're using the shell.

The shell defines the following four different profiles:

  • One that applies to all shells and all users of the computer.
  • One that applies to all users, but only to the Microsoft PowerShell shell.
  • One that applies to the current user and to all shells.
  • One that applies to the current user and only to the Microsoft PowerShell shell.

The concept of "all shells" can be a bit confusing. The terminology is rooted in some early development concepts of Windows PowerShell that didn't really make it into the final product. Today, the term "all hosts" would probably be more appropriate.

Shells, Hosts, and Profiles

You see, Windows PowerShell itself is a set of Microsoft .NET Framework assemblies. I like to refer to this part of the shell as the Windows Power­Shell engine because it contains the functionality that you generally think of as Windows PowerShell. There's no built-in way for humans to interact with this engine, though. For you to actually use the shell, the engine must be loaded by a hosting app (or host).

The powershell.exe application that you're probably used to running is one such host. The gpowershell.exe application included with the Windows PowerShell 2.0 Community Technology Preview (CTP) is another host. This relationship between hosts and shells isn't quite as simple as I've made it out to be here, but my simplified explanation covers the behavior you see.

It's important to understand that if you're interacting with the shell via a text-based command-line interface, then you're probably using the powershell.exe host. This applies even if you've launched the shell using a shortcut installed by another app, such as the Exchange Management Shell. The Exchange Management Shell isn't a different shell or hosting application. Rather, it's merely the normal powershell.exe host launched using a shortcut that specifies a set of snap-ins and scripts to be pre-loaded. Those snap-ins are what enable the Exchange management functionality within the shell. But you're still using the same shell.

The locations (on Windows Vista) of the profiles for the powershell.exe host are as follows:

  • %windir%\system32\Windows­PowerShell\v1.0\profile.ps1This is for all users of the computer and for all shells.
  • %windir%\system32\Windows­PowerShell\v1.0\Microsoft.Power­Shell_profile.ps1This is for all users of the computer, but it is only for the Microsoft.PowerShell shell.
  • %UserProfile%\Documents\Windows­PowerShell\profile.ps1This is for the current user only and all shells.
  • %UserProfile%\Documents\WindowsPowerShell\Micro­soft.PowerShell_profile.ps1This is for the current user only and only for the Microsoft.PowerShell shell.

These profiles aren't created by default. They exist only if you create them.

Each hosting application is responsible for loading and executing the correct profile. If a particular hosting application "decides" not to load any profiles at all, then it doesn't really have to. Profile execution is not performed by the Windows PowerShell engine automatically.

The easiest way to keep track of all this is to simply open the shell, type $profile, and hit Enter. That will give you the full path that the shell is attempting to use as what I think of as the "primary" profile (it's the per-user, shell-specific profile). You can then create or modify that script and it will execute each time the shell starts.

Using Your Profile

One common use for a profile is to define custom aliases, as I suggested earlier. Or you can add custom PSDrives (these are essentially mapped drives that exist entirely within Windows PowerShell). A less common use is to create a sort of super-shell that can do any management task you might need, based on the software products you're using in your environment. To really explain the super-shell concept, I first need to give a little bit of background information.

The product group within Microsoft that creates Windows PowerShell is responsible for many of the other core management technologies, including the Microsoft Management Console (MMC). The MMC provides a good analogy for just how Windows PowerShell works. When you run mmc.exe, you start with a blank console that isn't good for much. You add MMC snap-ins in order to create a functional console.

Once you've got your console configured the way you want, you save the console in a file with an .msc file name extension. This saved console file allows you to quickly reload your custom console at any time.

Rather than making custom MMC consoles, many admins just rely on the consoles that are installed along with the products they manage. Exchange Server, for example, creates a console that only contains the Exchange Server snap-in. Active Directory Users and Computers is another pre-created console that contains a single snap-in.

Windows PowerShell works in much the same way. The Exchange Management Shell icon installed with Exchange Server 2007 management tools is actually a shortcut to powershell.exe with instructions to load a console file. Shell console files have a .psc1 filename extension and contain a list of snap-ins to preload (much like an .msc file contains a list of snap-ins that the MMC preloads for you). However, you're not stuck using these pre-created shell consoles. You can create a custom console—just as you can with the MMC—and use that to accomplish all of your management tasks. Profiles play a key role in making this possible.

Making a Custom Console

To make a custom console, you should start by finding the full names of each snap-in you want to work with. Make sure all the necessary management tools are installed on your computer. Then, in Windows PowerShell, run Get-PSSnapin –registered. This will list all the registered, yet unloaded, snap-ins available. Then create or edit the appropriate Windows Power­Shell profile. Add the Add-PS­Snapin commands to load each snap-in that you always want to be available. This might include snap-ins for Exchange Server, System Center products, and third-party snap-ins, such as the Power­Shell Community Extensions. Then save your profile (remember to digitally sign the profile if your Windows Power­Shell execution policy requires it) and close the shell. Reopen the shell, and it will automatically load all of the snap-ins listed in your profile.

Another technique is to load all of your snap-ins into the shell (using Add-PSSnapin and the names of the snap-ins) and then run Export-Console to create a .psc1 console file that contains all the snap-ins you're currently using. You can then use this .psc1 console file to create a new Windows PowerShell shortcut that specifies the PSConsole­File parameter and your custom .psc1 file. That shortcut would then use your console, loading up all the specified snap-ins automatically.

More Profile Tricks

I use my Windows PowerShell profile to perform a number of other useful tasks each time the shell starts. Here's some of what happens when the shell starts on my system:

  1. I run Get-Credential for my Domain Administrator account, storing the results in a variable named $cred. This makes $cred available throughout the shell. I can then pass it to the –credential parameter of various cmdlets, such as the Get-WmiObject cmdlet. Since $cred stores the password, I can use those cmdlets without being prompted for a password.
  2. I run Cd C:\ so the shell starts in the root of my computer's C: drive.
  3. I run New-Alias of Out-File to create an alias named "of." This is so I can then use "of" instead of "Out-File." I use this a lot, so having the short alias defined is very handy.

I try to create a test key in the shell's HKLM: drive, which represents the HKEY_LOCAL_MACHINE portion of the registry. If an error occurs, then I know the shell was launched without elevated privileges. I usually require elevated privileges for the work I do, and this is just a quick way for me to know up front whether I have elevated privileges before I get into serious work.

I define a custom function named Ping-Address that accepts a computer name or IP address and returns a True or False value depending on whether the computer is pingable. I use this function a lot in my work, so having it defined in my profile makes it globally available in my shell.

Cmdlet of the Month: Get-WmiObject

The astute observer might notice that I'm covering a cmdlet that I've featured before, but I want to let you in on a cool twist that it offers. I often see administrators try to retrieve Windows Management Instrumentation (WMI) information from multiple computers, whose names are listed in a text file, using this technique:

Get-Content c:\computers.txt | ForEach-Object { Get-WmiObject Win32_Service –comp $_ }

While this technique works, you don't really need it because Get-WmiObject can accept an array of computer names for the –computerName parameter. To achieve the same effect, you can just use this:

Get-WmiObject Win32_Service –comp (Get-Content c:\computers.txt)

Placing the Get-Content command in parentheses forces the shell to execute the command and place the results—an array of computer names—into the –computerName parameter.

Profile Beware!

Keep in mind that powershell.exe isn't the only application that loads the Microsoft.PowerShell profiles or the all-shells profiles. Many integrated development environments (IDEs) that provide Windows PowerShell support—including PrimalScript from SAPIEN Technologies, PowerGUI from Quest Software, and PowerShell Plus from ShellTools—also load these same profiles to provide an experience that parallels the powershell.exe host.

A large profile that loads lots of snap-ins may cause these applications to start more slowly because there are a lot of instructions for the Windows PowerShell engine to carry out before it becomes ready for the hosting application. In fact, even powershell.exe can take a while to start up if you've got a very large profile script to execute.

Snap-ins that define cmdlets with the same names can cause collisions as well. For example, if two snap-ins define a cmdlet named Get-User, then Windows PowerShell won't execute either cmdlet until you use the fully qualified name of the cmdlet to specify which one you want. That fully qualified name can get ugly, since snap-in names can be quite long. When I run into this problem, I usually just give up on the idea of having those two snap-ins loaded simultaneously. Instead, I'll load only the one I use most in my profile and then use a separate, "fresh" shell when I need to load and use the other snap-in.

Windows PowerShell profiles can provide a great deal of extra convenience to the shell. But keep in mind that if they're maliciously edited by a piece of malware, profiles can also cause a great deal of damage. You can protect your profile by digitally signing it and configuring Windows Power­Shell to use its AllSigned execution policy, or modify the NTFS file permissions on your profiles—all of them—so that your normal user account can't modify them.

Don Jones is the author of Windows PowerShell: TFM and VBScript, WMI, and ADSI Unleashed. You can contact him through the Web site.