The Story Behind the Naming and Location of PowerShell Profiles

“<My Documents>\WindowsPowerShell\Microsoft.PowerShell_profile.ps1.”
“<Installation Directory>\Microsoft.PowerShell_profile.ps1.”

It’s probably the 63 characters in PowerShell that have the most thought behind them.  You might ask, “Could it be any longer?  More random?”

Sure!  Other considerations were:

PS:55 > $random = new-object Random

PS:56 > $output = $null1..100 | % { $output += [char]$random.Next(97122) }; "$output.ps1"

PS:57 > $output = $null1..100 | % { $output += [char]$random.Next(97122) }; "$output.ps1"

PS:58 > $output = $null1..100 | % { $output += [char]$random.Next(97122) }; "$output.ps1"

PS:59 > $output = $null1..100 | % { $output += [char]$random.Next(97122) }; "$output.ps1"



Actually, the reason we introduced the $profile variable is to make this as short as possible to you, while still serving our extensibility needs.

So, first off: “My Documents.”

A disconcerting trend is for applications to spew their files all over this directory.  “My Widgets,” “My eBooks,” etc.  They do this even if you’ve never launched the application, or used the given file.  Knowing that, we still ask users to place their profile in their “My Documents.”  This is for two reasons. 

First, we don't generate the files in this directory - they are user-authored documents, not application configuration files.  The folder will also contain other user-authored documents, such as types and formatting customizations.  Even more, the profile is one of a shell user's most treasured documents.  Users quickly consider this to be a vitally personal document - along with their .emacs / .vimrc.  The internet is full of these "dotfiles" that people are proud enough to share.  It is already one of the first and most common things that PowerShell users share. In Word, you generate Word documents.  In Excel, you generate spreadsheets. In PowerShell, you generate profiles, scripts, and ps1xml extension files.  If a user can't point their finger at a file in "My Documents" and remember putting it there, then it's in the wrong spot.

This used to be in a directory called "PsConfiguration" (to be consistent with the installation directory of the All Users' version.)  Since that is no longer where we store the machine-wide profile, this has now changed to a much more understandable "WindowsPowerShell."

Second, the “Application Data” is hidden by default.  That breaks tab completion, discoverability, and so much more for this commonly-used document.

Next: “<Installation Directory>” (for the all-user profiles)

We chose this location because it is the only reasonable and secure location to place a startup script that runs for every user.  If a malicious user can edit this file, they can add commands to it that will elevate that user to Administrator the next time the Administrator logs in (and automatically runs that profile script.) 

We used to store these files in a protected directory under "All Users Documents," but that could still cause security problems.  If the administrator deletes the folder from the “All Users” directory, the Windows ACL lets any user recreate it.  A malicious user could then add an auto-running profile there.

It should really go into an /etc directory, but that oddly seems to be missing in the version of Unix called Windows that I'm currently running 🙂

Finally, “Microsoft.PowerShell_profile.ps1”

The PowerShell model supports the concept of multiple shells (“hosts”).  For example, the PowerShell.exe console application is the host that most users will know and love.  It has a certain Shell ID.  Karl Prosser's PowerShell Analyzer is another shell.  It has its own Shell ID. In the future, we will have a GUI host that also has its own Shell ID.  You may want code that runs in one of those shells, but not the others. Profile code that accesses $host.UI.RawUI is something that you would probably want to be specific to a shell, for example.

In those situations, you would use the $profile variable. That variable refers to the user-specific profile for the current shell.  Its name derives primarily from the Shell ID of the current shell.  In contrast, the plain "profile.ps1" file is loaded for every shell.

Technically, the PowerShell engine loads profiles in the following order:

  1. "All users" profile is loaded from "<Installation Directory>\profile.ps1"
  2. "All users," host-specific profile is loaded from "<Installation Directory>\Microsoft.PowerShell_profile.ps1"
  3. Current user profile is loaded from "<My Documents>\WindowsPowerShell\profile.ps1"
  4. Current User, host-specific profile is loaded from "<My Documents>\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"

With only one shell (PowerShell.exe,) it doesn't really matter which you use if you use only PowerShell.exe.  I personally use the zenfully correct $profile to hold my modifications, though.

[Edit: Fixed typo in "All Users" document load location.  Thanks, Tony!]
[Edit 10/04/06: Updated to describe the more recent changes in RC2]

7 Responses to “The Story Behind the Naming and Location of PowerShell Profiles”

  1. Tony writes:

    PowerShell.exe does NOT load profile from "All users":

    # "All users" profile is loaded from "\Documents and settings\All users\PsConfiguration\profile.ps1"
    # "All users," host-specific profile is loaded from "\Documents and
    settings\All users\PsConfiguration\Microsoft.PowerShell_profile.ps1"

    I tried profile.ps1 and Microsoft.PowerShell_profile.ps1. Neither of them were load. I have no idea how this could happen.


  2. Lee writes:

    Thanks Tony. The path includes "Documents," which I so brazenly left out 🙂

  3. Hal Rottenberg writes:

    Lee, it has occurred to me that $profile is backwards. Shouldn’t it point to the non-host specific file, suitably named profile.ps1, rather than the host-specific Windows_Powershell.profile.ps1? In other words, your feng shui is out of whack!

  4. Josh Einstein writes:

    You know what would be great? If PowerShell also looked for profile_$($Environment.MachineName).ps1 as well.

    I already do this in my profile.ps1:

    $ProfileCurrentMachine = "profile_$([Environment]::MachineName).ps1"

    $PROFILE | Add-Member -Force `
    NoteProperty `
    CurrentUserCurrentMachine `
    "$(Split-Path $PROFILE.CurrentUserAllHosts)\$ProfileCurrentMachine"

    if ( Test-Path $PROFILE.CurrentUserCurrentMachine ) {
    . $PROFILE.CurrentUserCurrentMachine

  5. Aaron Hope writes:

    Josh, you’ve inspired me. For weeks I’ve flat-out refused to create a PowerShell profile under My Already Far Too Polluted Documents. Now my profile script comfortably resides with the other configuration files under AppData and I can let go of another little piece of frustration.

    $AppData = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ApplicationData)
    $CurrentUserAppData = "$AppData\WindowsPowerShell\profile.ps1"

    $PROFILE | Add-Member -Force NoteProperty CurrentUserAppData $CurrentUserAppData

    if ( Test-Path $PROFILE.CurrentUserAppData ) {
    . $PROFILE.CurrentUserAppData

  6. PowerShell Magazine » Pimp Your Profile writes:

    […] those details here. If you are curious about how profiles are implemented, then I recommend reading LeeHolmes‘  post on some of the history behind the decision […]

  7. Bob Goldman writes:

    I think MyDocuments would be an OK place to put files for consumers, but as developers we tend to keep our personal documents separate from our development work. The problem is that you cannot change this path easily and many powershell modules put their code into the default location. It is interesting that Microsoft chooses AppData for Outlook and My Docucuments for PowerShell. Do you realize how many people have lost years of email because they forgot to back up their AppData folder? Sorry your reasoning here doesn’t make much sense.

Leave a Reply