powershellpowershell-v6.0

What are PowerShell profile locations on Linux?


On Windows, not counting ISE or x86, there are four (4) profile scripts.

AllUsersAllHosts @ C:\Program Files\PowerShell\6\profile.ps1
AllUsersCurrentHost @ C:\Program Files\PowerShell\6\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts @ C:\Users\lit\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost @ C:\Users\lit\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

On Linux with pwsh 6.2.0 I can find only two locations.

CurrentUserAllHosts @ ~/.config/powershell/Microsoft.PowerShell_profile.ps1
CurrentUserCurrentHost @ ~/.config/powershell/profile.ps1

Are there any "AllUsers" profile scripts on Linux? If so, where are they?


Solution

  • tl;dr (also applies to Windows):


    Olaf provided the crucial pointer in comment:

    $PROFILE | select *  # short for: $profile | Select-Object -Property *
    

    shows all profile file locations, whether or not the individual profile files exist.

    E.g., on my Ubuntu machine with PowerShell installed in /home/jdoe/.powershell, I get:

    AllUsersAllHosts       : /home/jdoe/.powershell/profile.ps1
    AllUsersCurrentHost    : /home/jdoe/.powershell/Microsoft.PowerShell_profile.ps1
    CurrentUserAllHosts    : /home/jdoe/.config/powershell/profile.ps1
    CurrentUserCurrentHost : /home/jdoe/.config/powershell/Microsoft.PowerShell_profile.ps1
    Length                 : 62
    

    Note the presence of the [string] type's native Length property, which you could omit if you used
    $PROFILE | select *host* instead.

    That you can get the profile locations that way is not obvious, given that $PROFILE is a string variable (type [string]).
    PowerShell decorates that [string] instance with NoteProperty members reflecting all profile locations, which is why select (Select-Object) is able to extract them.

    Outputting just $PROFILE - i.e. the string value - yields /home/jdoe/.config/powershell/Microsoft.PowerShell_profile.ps1, i.e. the same path as its CurrentUserCurrentHost property, i.e. the path of the user-specific profile file specific to the current PowerShell host environment (typically, the terminal aka console).[1]

    You can verify the presence of these properties with reflection as follows, (which reveals their values too):

    $PROFILE | Get-Member -Type NoteProperty
    

    This means that you can also use regular property access and tab completion to retrieve individual profile locations; e.g.:

    # Use tab-completion to find a specific profile location.
    # Expands to .Length first, then cycles through the profile-location properties.
    $profile.<tab>  
    
    # Open the all-users, all-hosts profiles for editing.
    # Note: Only works if the file already exists.
    #       Also, you must typically run as admin to modify all-user profiles.
    Invoke-Item $profile.AllUsersAllHosts
    

    Convenience functions for getting profile locations and opening profiles for editing:

    The code below defines:

    function Get-Profile {
      <#
      .SYNOPSIS
      Gets the location of PowerShell profile files and shows whether they exist.
      #>
      [CmdletBinding(PositionalBinding=$false)]
      param (
        [Parameter(Position=0)]
        [ValidateSet('AllUsersAllHosts', 'AllUsersCurrentHost', 'CurrentUserAllHosts', 'CurrentUserCurrentHost')]
        [string[]] $Scope
      )
      
      if (-not $Scope) {
        $Scope = 'AllUsersAllHosts', 'AllUsersCurrentHost', 'CurrentUserAllHosts', 'CurrentUserCurrentHost'
      }
    
      foreach ($thisScope in $Scope) {
        [pscustomobject] @{
          Scope = $thisScope
          FilePath = $PROFILE.$thisScope
          Exists = (Test-Path -PathType Leaf -LiteralPath $PROFILE.$thisScope)
        }
      }
    
    }
    
    function Edit-Profile {
      <#
      .SYNOPSIS
      Opens PowerShell profile files for editing. Add -Force to create them on demand.
      #>
      [CmdletBinding(PositionalBinding=$false, DefaultParameterSetName='Select')]
      param (
        [Parameter(Position=0, ValueFromPipelineByPropertyName, ParameterSetName='Select')]
        [ValidateSet('AllUsersAllHosts', 'AllUsersCurrentHost', 'CurrentUserAllHosts', 'CurrentUserCurrentHost')]
        [string[]] $Scope = 'CurrentUserCurrentHost'
        ,
        [Parameter(ParameterSetName='All')]
        [switch] $All
        ,
        [switch] $Force
      )
      begin {
        $scopes = New-Object Collections.Generic.List[string]
        if ($All) {
          $scopes = 'AllUsersAllHosts', 'AllUsersCurrentHost', 'CurrentUserAllHosts', 'CurrentUserCurrentHost'
        }
      }  
      process {
        if (-not $All) { $scopes.Add($Scope) }
      }
    
      end {
        $filePaths = foreach ($sc in $scopes) { $PROFILE.$sc }
        $extantFilePaths = foreach ($filePath in $filePaths) {
          if (-not (Test-Path -LiteralPath $filePath)) {
            if ($Force) {
              if ((New-Item -Force -Type Directory -Path (Split-Path -LiteralPath $filePath)) -and (New-Item -Force -Type File -Path $filePath)) {
                  $filePath
              }
            } else {
              Write-Verbose "Skipping nonexistent profile: $filePath"
            }
          } else {
            $filePath
          }
        }
        if ($extantFilePaths.Count) {
          Write-Verbose "Opening for editing: $extantFilePaths"
          Invoke-Item -LiteralPath $extantFilePaths
        } else {
          Write-Warning "The implied or specified profile file(s) do not exist yet. To force their creation, pass -Force."
        }
      }
    
    }
    

    [1] PowerShell considers the current-user, current-host profile the profile of interest, which is why $PROFILE's string value contains that value. Note that in order to decorate a [string] instance with note properties, Add-Member alone is not enough; you must use the following idiom: $decoratedString = $string | Add-Member -PassThru propName propValue - see the Add-Member help topic.