Windows PowerShell Profiles Processing Illustrated

Hello everyone! My name is Preston K. Parsard (Platforms PFE) here again this time for a procedural review of PowerShell profiles. Now I realize that this topic is already well documented and in fact, have included some great references at the end of this post, where you can find more information. What I can offer here in addition to these sources is an illustrated step-by-step approach to explain how PowerShell profiles are loaded, processed and even relate to each other.

PURPOSE

Profiles can be used to establish a baseline set of features provided by references to variables, modules, aliases, functions and even PowerShell drives. Profiles can also enable a common set of experiences like colors for the various host on a system that will be shared among different engineers, like Dana and Tim in our upcoming scenario who will use the same development server. With these configurations, all users will have access to these resources and experiences by the time their individual user/host profile loads. In addition, individual profiles can be customized to each specific logged-on users own perferences. Even if a user or team of engineers need to log on to multiple systems, such as servers or workstations, they can still leverage a common set of resources by employing remote profiles hosted on a file share.

PRE-REQUISITES

Version
The tests and screenshots shown are based on Windows PowerSell version 5.1. The PowerShell console (Microsoft.PowerShell) and the Integrated Scripting Environment, (Microsoft.PowerShellISE) hosts will be covered.

Hosts
Hosts in this context refers to the PowerShell engine used such as the PowerShell console or the Integrated Scripting Environment (ISE), not the computer as in localhost. While there are other hosts that can be used for PowerShell, such as Visual Studio Code and Visual Studio 2017, among others, we will focus our discussion only on the native Windows PowerShell console and ISE engines and acknowledge that the process is similar in concept for all hosts, with the exception for where certain host profiles reside on the file system and how the host specific themes, apearance and layout for each host can be modified with profile settings.

Execution
Scripts cannot be executed using the default PowerShell execution policy, which is restricted, and since profiles are implemented as PowerShell scripts, this execution policy will have to be changed to allow script execution so that the profile scripts will run. You will also require administrative access in order to change the execution policy on a system.

SCENARIO
Adatum, a fictitous regional manufacturing company of 100 employees, has a team of Windows systems engineers who have recently been tasked with building their PowerShell script library. This repository will host new and existing scripts to automate routine tasks for the the Windows server team.
We will examine the PowerShell profile processing experience for one of the senior members of this team – Dana who will use login alias usr.g1.s1 and is a member of the local adminsitrators group on that machine. Dana will be logging on to the development domain of dev.adatum.com. There is also a usr.g2.s2 alias for the other engineer, Tim, but it will not be used for the demos however. In this scenario, we will use screenshots after Dana logs on to the Windows Server 2016 development server named AZRDEV1001.

Figure 1: Window PowerShell Profile Processing Flowchart.

PROFILE PROCESSING

Step 1:
Select machine.
Dana decides to examine and edit user profiles on the development server, AZRDEV1001, for all users who log on to create and run powershell scripts, as well as for her individual profiles for each host.
Step 2:
User logs on (select user).
Dana logs on to AZRDEV1001 and her user profile is loaded. This is the first time she is logging on to AZRDEV1001 as it is a newly provisioned server in Microsoft Azure for the team.
Step 3:
usr.g1.s1 user selects and opens host (Console or ISE).
Dana opens both the PowerShell console and the ISE, since she will be editing profile scripts using the script pane of the ISE. Before editing these profile scripts however, she needs to determine which ones already exist in each host and which ones must be created.
In the console host, Dana first sets the execution policy to RemoteSigned as follows.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
Afterwards, she issues the following commands shown below in figure 2.

Figure 2: Listing and verifying console profile path availability.

Figure 3: Creating the AllUsersAllHosts profile.

Figure 4: Creating the AllUsersCurrentHost profile.


Figure 5: The CurrentUserAllHosts path do not yet exist.

At this point, as shown in figure 5, Dana will have to create both the WindowsPowerShell directory as well as the profile.ps1 file for the CurrentUserAllHosts profile before editing it since neither currently exists.

New-Item -path $Home\Documents\WindowsPowerShell -ItemType Directory

New-Item -path $profile.CurrentUserAllHosts -ItemType File


Figure 6: Creating the CurrentUserAllHosts profile.


Figure 7: Creating the CurrentUserCurrentHost profile.

Dana now closes the console and opens the ISE using the run as Administrator option.


Figure 8: The …CurrentHost profiles are not available.

Notice that only the …AllHosts profiles 1 & 3, were pulled into the current session for the ISE host. Any guesses why?
Well it turns out that when the ISE opens, it will try to load the …CurrentHost profiles 2 & 4 for the ISE as a separate host. This is because Dana created the current hosts profile previously while she was in the console, not the ISE, so only the console specific …CurrentHost profiles were created.
This means that while Dana now has the ISE host opened, she will just need to create the two …CurrentHost, profiles, starting with AllUsersCurrentHost and then CurrentUserCurrentHost.
Unfortunately, as the console pane of the ISE here shows, these profiles do not yet exist and therefore must be created first to be loaded in any subsequent ISE sessions.


Figure 9: AllUsersCurrentHost and CurrentUsersCurrentHost profiles do not yet exist for the ISE host.


Figure 10: Creating the AllUsersCurrentHost and CurrentUserCurrentHost profiles.

Now Dana can edit and customize the …CurentHost profiles for the ISE using the psedit command.


Figure 11: Editing the AllUsersCurrentHost profile.


Figure 12: Editing the CurrentUserCurrentHost profile.

Dana has configured all profiles now, so she closes the ISE and we can continue to observe the results in the remaining steps.

Step 4c: Console host starts (Microsoft.PowerShell).
When the PowerShell console is invoked, it will first load the AllUsersAllHosts profile, which executes the profile script located at $PsHome\Profile.ps1, and usually resolves to: C:\Windows\System32\WindowsPowerShell\v1.0\Profile.ps1. 
Step 4i:
ISE host starts (Microsoft.PowerShellISE).
When the ISE loads, it will also execute the AllUsersAllHosts profile script as the first in the sequence of all the profile scripts, just as shown above in step 4c since it is common to all hosts.
Step 5:
[1] Host agnostic profile loads for any logged-on user (usr.g1.s1 or usr.g2.s2).
The AllUsersAllHosts profile script also loads for any user that logs on, so even if Tim borrowed Dana’s workstation and logs in with his user account usr.g2.s2, and opens either the PowerShell console or the ISE, or both, this PowerShell profile, if available will execute. It is universal in that it will load the profile for any user using any host.


Figure 13: AllUsersAllHosts profiles loaded.
Step 6c:
[2] Console host profile loads for any logged-on user (usr.g1.s1 or usr.g2.s2).
Since Dana did open the PowerShell console, the AllUsersCurrentHost script $PsHome\Microsoft.PowerShell_profile.ps1, which resolves to C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1 will then execute and load. This is the profile that Dana created and configured in figure4.

Figure 14: AllUsersCurrentHost profile loaded for the console host.
Step 6i:
[2] ISE host profile loads for current logged-on user (usr.g1.s1).
Dana also opened the ISE, which has its own version of the AllUsersCurrentHost profile script at $PsHome\Microsoft.PowerShellISE_profile.ps1, resolving to C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1 that Dana created previously in figure 11.

Figure 15: AllUsersCurrentHost profile loaded for the ISE host.
Step 7: [3] Host agnostic profile loads for current logged-on user (usr.g1.s1).
Next, the CurrentUserAllHosts profile script, if available will run and load its configuration from what is specified in the content of $Home\Documents\WindowsPowerShell\Profile.ps1 that expands to C:\Users\usr.g1.s1\Documents\WindowsPowerShell\Profile.ps1.
Note that this profile script will apply to both the PowerShell console host and the ISE for Dana, but only for Dana. Of course if Tim had logged on to AZRDEV1001, then the path would be different because Tim would have a separate user profile at C:\Users\usr.g2.s2, not
C:\Users\usr.g1.s1.
Step 8c:
[4] Console host profile loads for current logged-on user (usr.g1.s1).
Finally, the last user and host specific profile CurrentUserCurrentHost for the PowerShell console will load for Dana from $Home\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 (C:\Users\usr.g1.s1\ Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1).

Figure 16: Console host loaded for current user.
Step 8i: [4] ISE host profile loads for current logged-on user (usr.g1.s1).
The CurrentUserCurrentHost ISE specific profile for will also load for Dana, but the profile script filename is slightly different and includes “ISE”. The path is: $Home\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1 (C:\Users\usr.g1.s1\ Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1) and loads only if it is available, which as we know for this scenario, it is because Data created it in figure 12.

Figure 17: ISE host loaded for current user.
Step 9:
END. All available profiles loaded.
Figure 2: Shared and separate profiles for console and ISE hosts
At this point, all four (4) profiles per host are now loaded if, and only if they were available, otherwise they will be skipped and the next profile in the processing order will be loaded…if available. This is because each profile represents the complete path to its corresponding PowerShell script, which is dot sourced or pulled into the current host session as it starts up. Therefore, if a profile script in a set of 4 scripts isn’t available, it will be skipped as the host attempts to load each of them.

Figure 18: All profiles loaded for all hosts.
Dana had configured all profiles at the beginning, which is why we see the effective color settings and variable assignments here now.

Figure 19: Profile Loading Sequence and Relationships

Now that we’ve covered the details, let’s sumarize by reviewing the simpler Venn diagram in Figure 19 above to focus on just the profile loading sequence and their relationship to each host.

[1] We’ll start at item 5 which shows that for either the console or the ISE host, the AllUsersAllHosts profile at $PsHome\Profile.ps1 will load. Note in the diagram how this step is shared between both the console and the ISE since it appears in the intersection of both circles.
[2] If the console host was launched, then at 6c the AllUsersCurrentHost, located at $PsHome\Microsoft.PowerShell_profile.ps1 is pulled in to console session.
[2] If however the ISE was opened, even if the console was already opened, then 6i indicates that AllUsersCurrentHost will load. Although it has the same name as in 6c , it is specific for the ISE host, so the path directory will be identical, but the file will differ to reflect that it is associated with the ISE and not the console. This is represented by the full profile path of: $PsHome\Microsoft.PowerShellISE_profile.ps1
[3] In step 7 , which is another profile shared between hosts, CurrentUserAllHosts with the path value of $Home\[My] Documents\WindowsPowerShell\Profile.ps1 will be dot sourced into the loading session of either the console or the ISE, or even both if both are opened.
[4] For the console host, step 8c represents the CurrentUserCurrentHost profile, pointing to the path $Home\[My] Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1.
[4] So it’s no surpise that in 8i , although using the same profile name as 8cCurrentUserCurrentHost. This profile actually points to $Home\[My] Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1, because now we’re importing an ISE host specific profile instead of the console version.

User Host Sequence Shared between hosts Path
All All 1 Yes $PsHome\Profile.ps1
All Current 2 No $PsHome\Microsoft.<hostid>_profile.ps1
Current All 3 Yes $Home\[My] Documents\WindowsPowerShell\Profile.ps1
Current Current 4 No $Home\[My] Documents\WindowsPowerShell\<hostid>_profile.ps1

Figure 20: Profile patterns

Lets see if we can finally identify some common patterns to reinforce this review. Notice that in Figure 20, whenever there is an All host refence as in sequences 1 and 3, the profile script name will be Profile.ps1, otherwise the script name is represented as …<hostid>_profile.ps1 which is host dependent and uses the current host, such as for the AllUsersCurrentHost and CurrentUserCurrentHost profiles. Whenever we see a CurrentUser part of a profile name, it will be specific to the currently logged on user and therefore the full path to that users profile must begin with their user home directory at $Home. For example $Home will resolve to C:\Users\usr.g1.s1 for Dana and C:\Users\usr.g2.s2 for Tim if Tim were to log on and initialize his profile.

Shared Profiles
Now what if Dana and Tim both need to log into various systems in dev.adatum.com, but for convenience wanted to use the same set of shared scripts, functions, modules, variables and sourced form a single, common PowerShell profile?
Dana decides to configure this profile since she knows that she can dot source a shared profile script in any of thier CurrentUser… profiles (for either Dana or Tim), for each machine profile scripts by adding a line using the following syntax:
. //<server>/<share>/<SharedProfileScript.ps1>

First, she creates the remote \\azrweb1001\profiles share and sets the modify permissions to allow the group to which Tim and she belong – GS-AutomationTeam access to the shared profile. Dana then creates the profile on the network file share and edits it as shown in figure 22 below.


Figure 22: Creating a remote shared profile.

Next, Dana dot sources the remote profile as shown below in line 3.


Figure 23: Dot sourcing a remote profile in an existing profile for CurrentUserAllHosts.

Since the execution policy was originally set to RemoteSigned on AZRDEV1001, PowerShell will perceive network shares as remote locations and will insist that any scripts on the shares must be signed. Therefore, Dana must add the server on which the share resides to the local intranet zone in her browser advanced options.


Figure 25: Adding a server with shares to the local intranet zone.

Now when Dana open any hosts on AZRDEV1001, she sees that the remote profile will be loaded.


Figure 26: Remote profile loaded in ISE host.


Figure 27. Remote profile loaded in console host.

Cumulative Effect
Profiles are cumulative so that after the common baseline profile AllUserAllHosts loads, the remaining profiles will contribute their values to the final individual profile CurrentUserCurrentHost as well. This is why after a host fully loads, we see all the values for $profile1, $profile2, $profile3 and $profile4 that were assigned at each separate profile, confirming the cumulative effect.

Conflict Behavior
We observed that for the console host, although Dana set the foreground color to green, when the 4th profile loaded – CurrentUserCurrentHost, which specifies a foreground color of magenta, the resultant or effective color was magenta after-all. That’s because the most recent profile to load in the sequence wins, or last wins for short if there is a conflicting value.

Other Hosts
In case you’re still curious, here are the profile paths for some other hosts. Note that the …CurrentHosts profiles will include the hostid in the profile filenames.

PowerShell Tools for Visual Studio 2017
AllUsersAllHosts : C:\Windows\System32\WindowsPowerShell\v1.0\Profile.ps1
AllUsersCurrentHost : C:\Windows\System32\WindowsPowerShell\v1.0\PoshTools_profile.ps1
CurrentUserAllHosts : C:\Users\prestopa\Documents\WindowsPowerShell\Profile.ps1
CurrentUserCurrentHost : C:\Users\prestopa\Documents\WindowsPowerShell\PoshTools_profile.ps1

PowerShell Language Support for Visual Studio Code
AllUsersAllHosts : C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
AllUsersCurrentHost : C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.VSCode_profile.ps1
CurrentUserAllHosts : C:\Users\prestopa\Documents\WindowsPowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\prestopa\Documents\WindowsPowerShell\Microsoft.VSCode_profile.ps1

SUMMARY
The combination of hosts and users provides 4 possibilities; AllUsersAllHosts, AllUsersCurrentHost, CurrentUserAllHosts and CurrentUserCurrentHost. Given two hosts – the console and the ISE, there are a total of 6 profiles, 2 of which are common for AllHosts + 2 that are host dependent for the console + 2 that are host dependent for the ISE. If it makes it easier, you can try the abbreviations for the processing order, and also consider that users must log on before they open a particular host, so we list the users profile condition before the host condition (AllUsers… or CurrentUsers…). Also, notice that the All conditions always gets evaluated first, both for users and then for hosts.

  1. AUAH (AllUsersAllHosts)
  2. AUCH (AllUsersCurrentHost)
  3. CUAH (CurrentUserAllHosts)
  4. CUCH (CurrentUserCurrentHost)

See the pattern now?

Well that’s it for now friends. I hope that you have a better understanding of how profiles are loaded and relate to each other. If it hasn’t sunk in immediately, just keep this post as a handy reference and rely on the visual cues from the diagrams and table as a quick guide. If you do this often enough, plus use the references listed below, your comprehension of PowerShell profiles will continue to grow.

Happy scripting!

REFERENCES

Index Title Type Link
1 about_Profiles Microsoft Docs Link
2 Understanding the Six PowerShell Profiles TechNet Link
3 How to Use Profiles in Windows PowerShell ISE Microsoft Docs Link
4 Persistent PowerShell: the PowerShell Profile Simple-Talk (www.redgate.com) Link
5 Getting Started with PowerShell Profiles YouTube Video Link
6 Use a Central File to Simplify Your PowerShell Profile TechNet (Scripting Guy) Link