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.25
#
#  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') {
      if ((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
After installing the profile, when PowerShell is started the next time, the error script cannot be loaded because running scripts is disabled on this system might be thrown.
The link has some tips what to do in such a case.

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
V.25 Check if platform is windows before checking if running on VirtualBox - only then assing $virtEnv.

See also

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

Index

Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database in /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php:78 Stack trace: #0 /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php(78): PDOStatement->execute(Array) #1 /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php(30): insert_webrequest_('/notes/developm...', 1758200931, '216.73.216.150', 'Mozilla/5.0 App...', NULL) #2 /home/httpd/vhosts/renenyffenegger.ch/httpsdocs/notes/development/tools/scripts/personal/profile_ps1(330): insert_webrequest() #3 {main} thrown in /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php on line 78