Understanding different (Six and more!) PowerShell profiles

As you know, PowerShell profiles are a great way to store persistent PowerShell settings which applies whenever you start a new session. So, if a profile is good, wouldn’t it be good if you can have multiple profiles. It turns out that any single PowerShell session may use a number of profiles and different PowerShell hosts provide yet more choices. By default, PowerShell (and ISE) provides six different choices out of the box. In this blog post, we are going to understand these one.

Understanding host and Shell

The first thing to understand is that there is difference between shell and host in PowerShell. Do note that you (as in a user typing at the keyboard) do not directly interact with PowerShell’s shell (or engine). Rather more accurately, you interact with a host application (like powershell.exe or powershell_ise.exe) that creates a runspace (an instance of the PowerShell engine). You can actually see the distinction by displaying the contents of the Name property of the $Host system variable alongside the $ShellId variable.

You will see that, if you examine the values for the three most common PowerShell hosts, they all use the same engine (shell) while each presents a different user interface (host).

Host $Host.Name $ShellId
PowerShell ConsoleHost Microsoft.PowerShell
PowerShell ISE Windows PowerShell ISE Host Microsoft.PowerShell
Visual Studio Package Manager Console Package Manager Host Microsoft.PowerShell

Other hosts like Visual Studio Code or 3rd party tools can have potentially different $ShellId values.

Understanding PowerShell Profiles

Quote from about_profiles article from MSDN, “A Windows PowerShell profile is a script that runs when Windows PowerShell starts. You can use the profile as a logon script to customize the environment. You can add commands, aliases, functions, variables, snap-ins, modules, and Windows PowerShell drives. You can also add other session-specific elements to your profile so they are available in every session without having to import or re-create them.”

So, in short, a profile is nothing more than a fancy script which runs whenever you start a new PowerShell session in host of your choice. Each PowerShell host actually supports two profiles, one is user-level, distinct for each user, and the other is system-level, common to all users. This should be a familiar paradigm that you will have seen with many Windows applications. PowerShell adds its own unique twist, though: it similarly distinguishes between host-level (one profile for each host) and system-level (one common profile for all hosts).

Thus, taking all the combinations of users and hosts, you could potentially use any (or all) of four different profiles:

  • AllUsersAllHosts
  • AllUsersCurrentHost
  • CurrentUserAllHosts
  • CurrentUserCurrentHost

Understanding precedence of Profiles

As mentioned, all profiles can peacefully co-exist at same time. So its necessary to understand its order of execution or which profile takes precedence over which one. For easy to understand purpose, we have mentioned above profiles in order of execution precedence. So AllUsersAllHosts executes first followed by AllUsersCurrentHost and so on.

If you were to define the same variable in all four profiles, the variable will, once you launch a PowerShell host and finally receive a prompt, have the value assigned by the last profile, CurrentUserCurrentHost, because each successively processed profile will overwrite that variable with its value.

Role of $Profile variable

To create or edit any of the profiles, of course, you need to know where to find them. PowerShell itself can easily tell you, but it can also just open one for editing without you having to explicitly bother with the path. When you query the $profile automatic variable, it returns the path to the CurrentUserCurrentHost profile. Here’s value from my machine:

value-of-profile-variable
Value of Profile variable

Inside the Windows PowerShell ISE, when I query the $profile automatic variable, I receive the below output:

value-of-profile-variable-in-ise
Value of Profile variable in ISE

The difference between the Windows PowerShell console CurrentUserCurrentHost profile path and the Windows PowerShell ISE CurrentUserCurrentHost profile path is three letters: ISE.

If you pipe the output of $profile variable and filter by NoteProperty type, you can see all 4 profiles path. Here’s a value from my machine for powershell.exe:

get-values-of-all-4-profile-paths-associated
Getting values of all 4 profiles associated with a host

And in ISE:

get-values-of-all-4-profiles-for-ise
Getting values of all 4 profiles associated with ISE

You can also get a specific profile (out of 4 mentioned above) by using its reference name:

get-specific-profile-associated-with-a-host
Get specific profile associated with a host

Substitute any of the other three profile property names to access one of the non-default profiles.

Determine if a specific $Profile exists

Note that the path only mentions the location at which you can find the profile. It does not necessitates and by default, no profile exists at mentioned location. You can simply test this using Test-Path cmdlet:

checking-if-a-specific-profile-exists
Checking if specific profile exists

In my case, I am using custom profile for powershell.exe, so value of CurrentUserCurrentHost is true. By default, it should be false for you.

Creating a new Profile

If profile does not exist, it can be created using New-Item cmdlet easily:

if (!(Test-Path $Profile)) {
    New-Item -Type file -Path $Profile -Force 
}
By default, it defaults to CurrentUserCurrentHost. You can mention specific profile name also like below:
if (!(Test-Path $Profile.AllUsersAllHost)) {
    New-Item -Type file -Path $Profile.AllUsersAllHost -Force
}

We have also explained this in a previous post.

Profile file Name and locations

Below table shows path of each profile:
Description Path
Current User, Current Host – console $Home\[My ]Documents\WindowsPowerShell\Profile.ps1
Current User, All Hosts $Home\[My ]Documents\Profile.ps1
All Users, Current Host – console $PsHome\Microsoft.PowerShell_profile.ps1
All Users, All Hosts $PsHome\Profile.ps1
Current user, Current Host – ISE $Home\[My ]Documents\WindowsPowerShell\Microsoft.P owerShellISE_profile.ps1
 All users, Current Host – ISE $PsHome\Microsoft.PowerShellISE_profile.ps1

Reviewing the locations, it is simple to understand the naming conventions. The system-level profiles-those for all users-are in the system directory pointed to by $PsHome. The user-level profiles are under each user’s home directory. The one point that needs explanation is the HostId shown for the host-specific profiles in the table. Unfortunately, this host id bears no direct resemblance to the host description nor to the $Host.Name property! The way to discover the HostId is simply to display the value of the $Profilevariable, as it is part of the path. For convenience, here are the HostId values for the most common hosts:

Host HostId $Host.Name
PowerShell Microsoft.PowerShell ConsoleHost
PowerShell ISE Microsoft.PowerShellISE Windows PowerShell ISE Host

Deciding on Profile to be used

Any standard Windows system has two profiles for the standard PowerShell host, two for the PowerShell ISE host, and two for all hosts-six in all as a minimum. Each IDE adds 2 more to the kitty.

Interpreting official about_profiles article from MSDN consider below solution.

  • Put truly common things in AllUsersAllHost.
  • If there are some peculiarities in particular hosts, use AllUsersCurrentHost for those miscreant hosts.
  • Let each user manage his/her own preferences and settings in user-specific profiles.

Again point 3 can be specific to each IDE including Microsoft’s own PowerShell ISE. So in a nutshell, it’s all up to you. That’s all to know about profiles for this post.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s