Search notes:

Script: profile.ps1

A startup script for powershell.

Some functions

update-profile Update the profile script from github (Compare with Install the profile)
prompt Customizes the prompt to include the «next» history id (to be used with tab completion and #…) and to replace the backward slash with a forward slash. Print the value of $lastExitCode in red if it differs from 0.
admin 2021-08-10 (V.14): moved to the separate script file admin.ps1
cd A function that replaces the default alias cd so that it sets the (new) variable $oldPWD (see $pwd) and cd - changes to the directory I came from (as being used from a Unix shell) (Idea adapted from Venkut Naidu's Github gist)
paths 2021-08-02 (V.13): moved to a separate script file.

profile.ps1

#  V0.24
#
#  Note to self: create file %userprofile%\psh.bat with following content:
#
#    @powershell -executionpolicy bypass -noExit -file c:\lib\Scripts\profile.ps1
#

set-strictMode -version 3

# V.21: use script variable for hostname:
# V.24: remove .exe for Linux compatibility
$script:hostname = hostname

# v.22: Add global variable PPID (parent process id)
if ($psVersionTable.psEdition -eq 'Desktop') {
   $global:PPID = (get-cimInstance -className win32_process  -filter "processId = $PID").parentProcessId
}
else {
   $global:PPID = (get-process | where-object id -eq $pid).parent.id # | select-object {  $_.parent.id })
}

#
#  Update «this» profile script from github
#
function update-profile { invoke-webRequest https://raw.githubusercontent.com/ReneNyffenegger/scripts-and-utilities/master/profile.ps1 -outFile $profile }

function prompt {

   #
   # V0.10: Use prompt to write lastExitCode in red if lastExitCode <> 0
   #
   if ( (test-path variable:lastExitCode) -and $global:lastExitCode) {
      $error = "$([char]0x1b)[91mlastExitCode = $global:lastExitCode$([char]0x1b)[0m`n"
      $global:lastExitCode = 0
   }
   else {
      $error = ''
   }

   # Get the built-in prompt function (before overriding it)
   # with
   #   (get-command prompt).ScriptBlock
   #
   # It is:
   #   "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";

   # @( … ) creates an array even if get-history returns 0 or 1 elements.
   $hist = @( get-history )
   $thisId = 0
   if ($hist.count -gt 0) {
      $thisId = $hist[-1].id
   }

#  $curDir = get-location
#  $curDir = $executionContext.sessionState.path.currentLocation
   $curDir = $pwd


 # 2021-02-26: Print current directory with forward slashes instead
 #             of backward slashed:
   $curDir = $curDir -replace '\\', '/'

   $brackets = '>' * ($nestedPromptLevel + 1)


   $virtEnv = $false
#  if ([System.OperatingSystem]::IsWindows()                  -and (get-wmiObject win32_computersystem).model -eq 'VirtualBox')
   if ([System.Environment]::OSVersion.Platform -eq 'Win32NT' -and (get-wmiObject win32_computersystem).model -eq 'VirtualBox')
   {
      $virtEnv = $true
   }
#  elseif ([System.OperatingSystem]::IsLinux())
   else {
      systemd-detect-virt --quiet
      if (-not $lastExitCode) {
         $virtEnv = $true
      }
   }

   if ($virtEnv) {
    #
    # V.20: Include computername (hostname) if running in a VirtualBox
    #
      $prompt = "$($thisId+1) $script:hostname $curDir$brackets "
   }
   else {
      $prompt = "PS: $($thisId+1) $curDir$brackets "
   }

  "$error$prompt"
}

# { V.23: Different actions if started from cmd.exe

if ( (get-process -id $PPID).name -eq 'cmd') { # If started from cmd.exe: Set default colors for console

   $host.ui.rawUI.backgroundColor = 'black'
   $host.ui.rawUI.foregroundColor = 'white'
     # Change error colors etc. via
     #   $host.privateData.…
     # Get a list of possible values
     #   [enum]::GetValues([consoleColor])
   clear-host

}
else {
   if ($pwd -match 'system32$') {
     cd $home
   }
}

# }

# Equivalent of «dir /od» in cmd.exe
function dod {
   param (
      [validateScript( { test-path $_ } )]
      [string]                     $dir = '.'
   )

   get-childItem $dir | sort-object lastWriteTime
}

# Equivalent of «dir /s /b» in cmd.exe  ( http://stackoverflow.com/a/1479683/180275 )
function dsb($pattern) { get-childItem -filter $pattern  -recurse -force | select-object -expandProperty fullName }

function cdnot() {
   cd $env:notes_dir/notes
}

# Change behaviour of cd {
#
# Introduce  $OLDPWD and the dash option.
# Using cd sets $OLDPWD to the directory
# I came from. 'cd -' goes to $OLDPWD.
#
# Code was found @ https://gist.github.com/naiduv/c975528f02aed8e20232dfb366b41e14

remove-item alias:cd

function cd($newPWD) {

  if (-not $newPWD) {
     return
  }

  if ($newPWD -eq '-') {
      $newPWD = $global:oldPWD;
  }

  if (! (test-path $newPWD)) {
     write-host -foreGroundColor red "directory $newPWD does not exist"
     return
  }

  $curPWD = get-location
  set-location $newPWD
  $global:oldPWD = $curPWD
}
# }


set-psReadLineOption -editMode  vi    # vi editing mode;
set-psReadLineOption -bellStyle none  # no more distracting beeps

Function global:TabExpansion2 {
#
#   V0.11: Modify function TabExpansion2 so that it does not
#          show *.swp files when tab-expanding files.
#
#   Most of the function was copied from
#         (get-command TabExpansion2).ScriptBlock
#
    [CmdletBinding(DefaultParameterSetName = 'ScriptInputSet')]
    Param(
        [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 0)]
        [string] $inputScript,

        [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 1)]
        [int] $cursorColumn,

        [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 0)]
        [System.Management.Automation.Language.Ast] $ast,

        [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 1)]
        [System.Management.Automation.Language.Token[]] $tokens,

        [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 2)]
        [System.Management.Automation.Language.IScriptPosition] $positionOfCursor,

        [Parameter(ParameterSetName = 'ScriptInputSet', Position = 2)]
        [Parameter(ParameterSetName = 'AstInputSet', Position = 3)]
        [Hashtable] $options = $null
    )

    End
    {
       [System.Management.Automation.CommandCompletion] $cmdCompletion = $null
        if ($psCmdlet.ParameterSetName -eq 'ScriptInputSet')
        {
          #
          # Changed original source here: return -> $cmdCompletion =
          #
            $cmdCompletion = [System.Management.Automation.CommandCompletion]::CompleteInput(
                <#inputScript#>  $inputScript,
                <#cursorColumn#> $cursorColumn,
                <#options#>      $options)
        }
        else
        {
          #
          # Changed original source here: return -> $cmdCompletion =
          #
            $cmdCompletion = [System.Management.Automation.CommandCompletion]::CompleteInput(
                <#ast#>              $ast,
                <#tokens#>           $tokens,
                <#positionOfCursor#> $positionOfCursor,
                <#options#>          $options)
        }

       [System.Management.Automation.CompletionResult[]] $filtered = @( $cmdCompletion.CompletionMatches | where-object {
    #
    #     The type of $_ is System.Management.Automation.CompletionResult.
    #
    #     Only return file names that don't end in *.swp
    #
              $_.CompletionText -notMatch '\.swp$'
          } )

       [System.Collections.ObjectModel.Collection`1[System.Management.Automation.CompletionResult]] $res = $filtered

        $cmdCompletion= new-object System.Management.Automation.CommandCompletion $res, $cmdCompletion.currentmatchIndex, $cmdCompletion.replacementIndex, $cmdCompletion.replacementLength
        return $cmdCompletion
    }
}

$errorActionPreference = 'stop'

$psDefaultParameterValues['*:encoding'] = 'utf8'
Github repository scripts-and-utilities, path: /profile.ps1

Install the profile

$null = new-item -itemType directory (split-path $profile) -errorAction silentlyContinue
invoke-webRequest https://raw.githubusercontent.com/ReneNyffenegger/scripts-and-utilities/master/profile.ps1 -outFile $profile

History

V.10 Evaluate $lastExitCode and write it in red in the prompt if it is different from red. (2021-07-28)
V.11 Add customized TabExpansion2 function to filter *.swp* (VIM swap files) in tab completion. (2021-07-29)
V.12 Reset $lastExitCode in function prompt (as per new insight given by Michael Klement's StackOverflow answer); add set-strictMode -version 3 (2021-08-01)
V.13 Remove function paths and put it in its own file.
V.14 Remove function admin and put it into admin.ps1
V.15 set-psReadLineOption -bellStyle none
V.16 Move function pc to its own script pc.ps1
V.17 Move function fb to its own script fb.ps1
V.18 Set key *:encoding in psDefaultParameterValues.
V.19 use $notes_dir
V.20/21 Show value of $env:computername (hostname) in prompt (if running in VirtualBox?)
V.22 Add global variable $PPID (which stores the parent process ID, compare with $PID
V.23 Take different actions if started from cmd.exe
V.24 Make script more Linux friendly

See also

The automatic variable $profile stores the name of the profile script.
Scripts

Index