Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # -------------------------------------------------------------------
- # PowerShell Profile for Windows PowerShell 5.1
- # -------------------------------------------------------------------
- # This profile customizes the PowerShell experience with best practices:
- # - Leaves the current directory unchanged in normal sessions
- # - Redirects away from C:\Windows\System32 to the user's home directory
- # - Provides a clean, colored prompt indicating elevation status
- # - Includes useful functions with proper help and parameter validation
- # - Loads Chocolatey tab completion if available
- # -------------------------------------------------------------------
- # If PowerShell starts in C:\Windows\System32, move to the user's home directory
- $currentPath = (Get-Location).ProviderPath
- $system32Path = (Join-Path $env:WINDIR 'System32')
- if ($currentPath -ieq $system32Path) {
- Set-Location -Path $HOME
- }
- # Detect administrative privileges (calculated once for efficiency)
- $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
- [Security.Principal.WindowsBuiltInRole]::Administrator)
- # Custom prompt function
- function Prompt {
- # Set prompt prefix color: Red for admin, Green for normal user
- $color = if ($IsAdmin) { 'Red' } else { 'Green' }
- Write-Host 'PS' -NoNewline -ForegroundColor $color
- Write-Host " $((Get-Location).Path)" -NoNewline -ForegroundColor Cyan
- Write-Host '>' -NoNewline -ForegroundColor $color
- # Important: Return a string (with a trailing space) to complete the prompt
- return ' '
- }
- # -------------------------------------------------------------------
- # Function: Get-FolderSize
- # -------------------------------------------------------------------
- <#
- .SYNOPSIS
- Calculates the total size of files in a directory and its subdirectories.
- .DESCRIPTION
- Recursively enumerates files under the specified path, sums their sizes,
- and returns a custom object with file count, total size in bytes, and
- formatted size in MB/GB (auto-scaled for readability).
- .PARAMETER Path
- The directory path to measure. Defaults to the current location.
- .EXAMPLE
- Get-FolderSize -Path "C:\Users\$env:USERNAME\Documents"
- .EXAMPLE
- Get-FolderSize | Format-Table
- #>
- function Get-FolderSize {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory = $false, Position = 0)]
- [ValidateNotNullOrEmpty()]
- [string]$Path = (Get-Location).Path
- )
- $files = Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue
- if (-not $files) {
- Write-Warning "No files found in '$Path' or access denied to some subfolders."
- return
- }
- $measure = $files | Measure-Object -Property Length -Sum
- $totalBytes = $measure.Sum
- # Auto-scale to MB or GB
- if ($totalBytes -ge 1GB) {
- $formattedSize = '{0:N2} GB' -f ($totalBytes / 1GB)
- } elseif ($totalBytes -ge 1MB) {
- $formattedSize = '{0:N2} MB' -f ($totalBytes / 1MB)
- } else {
- $formattedSize = '{0:N2} KB' -f ($totalBytes / 1KB)
- }
- [PSCustomObject]@{
- Path = (Resolve-Path -Path $Path).Path
- FileCount = $measure.Count
- TotalBytes = $totalBytes
- Size = $formattedSize
- }
- }
- # -------------------------------------------------------------------
- # Chocolatey Tab Completion
- # -------------------------------------------------------------------
- # Load Chocolatey profile for tab completion if installed
- $ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
- if (Test-Path -Path $ChocolateyProfile) {
- Import-Module -Name $ChocolateyProfile
- }
- # -------------------------------------------------------------------
- # Function: Remove-PSReadLineHistoryEntry
- # -------------------------------------------------------------------
- <#
- .SYNOPSIS
- Deletes entries from the PSReadLine persistent history file by line number.
- .DESCRIPTION
- Removes one or more specific lines from the file at (Get-PSReadLineOption).HistorySavePath.
- This is the same numbering you see in `rh`, which shows the 1-based line number in the
- PSReadLine history file (not the session history Id used by Get-History/Clear-History).
- .PARAMETER LineNumber
- One or more 1-based line numbers to delete.
- .PARAMETER PassThru
- If set, outputs objects describing what was deleted.
- .EXAMPLE
- Remove-PSReadLineHistoryEntry 1947
- .EXAMPLE
- 1947,1952 | Remove-PSReadLineHistoryEntry -PassThru
- #>
- function Remove-PSReadLineHistoryEntry {
- [CmdletBinding(SupportsShouldProcess = $true)]
- param(
- [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
- [ValidateRange(1, [int]::MaxValue)]
- [int[]]$LineNumber,
- [switch]$PassThru
- )
- $historyPath = (Get-PSReadLineOption).HistorySavePath
- if (-not (Test-Path -Path $historyPath)) {
- Write-Error "History file not found at '$historyPath'."
- return
- }
- $targets = $LineNumber | Sort-Object -Unique
- $lines = [System.IO.File]::ReadAllLines($historyPath)
- $max = $lines.Count
- $bad = $targets | Where-Object { $_ -lt 1 -or $_ -gt $max }
- if ($bad) {
- Write-Warning ("Ignoring out-of-range line number(s): {0}. Valid range is 1..{1}." -f ($bad -join ', '), $max)
- $targets = $targets | Where-Object { $_ -ge 1 -and $_ -le $max }
- if (-not $targets) { return }
- }
- $toDelete = foreach ($n in $targets) {
- [PSCustomObject]@{
- LineNumber = $n
- Command = $lines[$n - 1]
- }
- }
- # Always write a backup alongside the history file.
- $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
- $backup = "$historyPath.bak.$stamp"
- Copy-Item -Path $historyPath -Destination $backup -Force
- if (-not $PSCmdlet.ShouldProcess($historyPath, "Delete PSReadLine history line(s): $($targets -join ', ')")) {
- return
- }
- # Remove from bottom-up to keep indexes stable.
- $list = New-Object 'System.Collections.Generic.List[string]' (, $lines)
- foreach ($n in ($targets | Sort-Object -Descending)) {
- $list.RemoveAt($n - 1)
- }
- [System.IO.File]::WriteAllLines($historyPath, $list, [System.Text.UTF8Encoding]::new($false))
- # Best-effort: refresh in-memory history for this session so UpArrow / Ctrl+R reflect the deletion.
- try {
- [Microsoft.PowerShell.PSConsoleReadLine]::ClearHistory()
- foreach ($l in $list) {
- if ($l -and $l.Trim()) {
- [Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($l)
- }
- }
- } catch {
- # If PSReadLine isn't available for some reason, just leave it.
- }
- if ($PassThru) {
- return $toDelete
- }
- foreach ($d in $toDelete) {
- Write-Host ("Deleted {0}: {1}" -f $d.LineNumber, $d.Command)
- }
- Write-Host ("Backup written to: {0}" -f $backup)
- }
- # -------------------------------------------------------------------
- # Function: Invoke-HistoryCommand
- # -------------------------------------------------------------------
- <#
- .SYNOPSIS
- Searches PowerShell history for unique commands matching a term and re-runs a selected one.
- .DESCRIPTION
- Displays unique commands from history that start with the optional search term,
- numbered for selection.
- At the prompt you can:
- - Enter a number to re-run the command
- - Enter `d <number>` (or `del <number>`) to delete that history line
- .PARAMETER SearchTerm
- Optional prefix to filter history commands.
- .PARAMETER Delete
- Deletes one or more PSReadLine history lines by number (the same numbers shown by `rh`).
- .EXAMPLE
- rh clear
- .EXAMPLE
- rh -Delete 1947
- #>
- function Invoke-HistoryCommand {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory = $false, Position = 0)]
- [string]$SearchTerm = '',
- [Parameter(Mandatory = $false)]
- [ValidateRange(1, [int]::MaxValue)]
- [int[]]$Delete
- )
- if ($Delete) {
- Remove-PSReadLineHistoryEntry -LineNumber $Delete
- return
- }
- # Ensure PSReadLine is available (built-in for PS 5.1)
- $historyPath = (Get-PSReadLineOption).HistorySavePath
- if (-not (Test-Path -Path $historyPath)) {
- Write-Error "History file not found at '$historyPath'."
- return
- }
- $historyLines = Get-Content -Path $historyPath
- # Filter and collect unique commands (preserving most recent occurrence)
- $unique = [ordered]@{}
- for ($i = $historyLines.Count - 1; $i -ge 0; $i--) {
- $line = $historyLines[$i].Trim()
- if ($line -and ($SearchTerm -eq '' -or $line -like "$SearchTerm*") -and -not $unique.Contains($line)) {
- $unique[$line] = $i + 1 # 1-based line number for display
- }
- }
- if ($unique.Count -eq 0) {
- Write-Host "No matching commands found in history."
- return
- }
- # Display numbered list (most recent first)
- $unique.GetEnumerator() | ForEach-Object {
- Write-Host ("{0,4}: {1}" -f $_.Value, $_.Key)
- }
- # Prompt for selection
- $selection = Read-Host -Prompt "Enter number to re-run, or 'd <number>' to delete (empty to cancel)"
- if (-not $selection) { return }
- # Delete mode: d 1947 / del 1947,1950
- $deleteMatch = [regex]::Match($selection, '^\s*(d|del|delete)\s+(.+?)\s*$', 'IgnoreCase')
- if ($deleteMatch.Success) {
- $raw = $deleteMatch.Groups[2].Value
- $tokens = $raw -split '[,\s]+' | Where-Object { $_ }
- $nums = New-Object 'System.Collections.Generic.List[int]'
- foreach ($t in $tokens) {
- $n = 0
- if ([int]::TryParse($t, [ref]$n) -and $n -ge 1) {
- [void]$nums.Add($n)
- } else {
- Write-Warning "Ignoring invalid line number token: '$t'"
- }
- }
- if ($nums.Count -gt 0) {
- Remove-PSReadLineHistoryEntry -LineNumber ($nums.ToArray())
- }
- return
- }
- # Run mode: just a number
- $chosenNumber = 0
- if (-not [int]::TryParse($selection, [ref]$chosenNumber)) {
- Write-Warning "Invalid input: '$selection' is not a number (or 'd <number>')."
- return
- }
- $match = $unique.GetEnumerator() | Where-Object { $_.Value -eq $chosenNumber } | Select-Object -First 1
- if (-not $match) {
- Write-Warning "No command found for number '$chosenNumber'."
- return
- }
- $chosenLine = $match.Key
- Write-Host "Executing: $chosenLine" -ForegroundColor Yellow
- Invoke-Expression -Command $chosenLine
- }
- # -------------------------------------------------------------------
- # Convenience Functions
- # -------------------------------------------------------------------
- <#
- .SYNOPSIS
- Opens the current PowerShell profile in Notepad++ when available.
- #>
- function Edit-Profile {
- [CmdletBinding()]
- param()
- if (-not (Test-Path -Path $PROFILE)) {
- New-Item -ItemType File -Path $PROFILE -Force | Out-Null
- }
- $editor = Get-Command notepad++ -ErrorAction SilentlyContinue
- if ($editor) {
- & $editor.Source $PROFILE
- } else {
- notepad $PROFILE
- }
- }
- <#
- .SYNOPSIS
- Creates a directory if needed, then enters it.
- .PARAMETER Path
- Directory path to create and enter.
- #>
- function New-AndEnterDirectory {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory = $true, Position = 0)]
- [ValidateNotNullOrEmpty()]
- [string]$Path
- )
- if (-not (Test-Path -Path $Path)) {
- New-Item -ItemType Directory -Path $Path -Force | Out-Null
- }
- Set-Location -Path $Path
- }
- <#
- .SYNOPSIS
- Changes to the dedicated Codex workspace.
- #>
- function Enter-CodexWorkspace {
- [CmdletBinding()]
- param()
- Set-Location -Path 'C:\Users\J2897\Codex'
- }
- <#
- .SYNOPSIS
- Launches Codex in the dedicated workspace.
- #>
- function Start-CodexWorkspace {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & codex --cd 'C:\Users\J2897\Codex' @Arguments
- }
- <#
- .SYNOPSIS
- Launches Codex in the dedicated workspace with live web search enabled.
- #>
- function Start-CodexWorkspaceSearch {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & codex --cd 'C:\Users\J2897\Codex' --search @Arguments
- }
- <#
- .SYNOPSIS
- Resumes the most recent Codex session for the dedicated workspace.
- #>
- function Resume-CodexWorkspace {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- Push-Location 'C:\Users\J2897\Codex'
- try {
- & codex resume --last @Arguments
- }
- finally {
- Pop-Location
- }
- }
- <#
- .SYNOPSIS
- Opens the user-level Codex configuration file in Notepad++ when available.
- #>
- function Edit-CodexConfig {
- [CmdletBinding()]
- param()
- $configPath = Join-Path $HOME '.codex\config.toml'
- $configDir = Split-Path -Parent $configPath
- if (-not (Test-Path -Path $configDir)) {
- New-Item -ItemType Directory -Path $configDir -Force | Out-Null
- }
- if (-not (Test-Path -Path $configPath)) {
- New-Item -ItemType File -Path $configPath -Force | Out-Null
- }
- $editor = Get-Command notepad++ -ErrorAction SilentlyContinue
- if ($editor) {
- & $editor.Source $configPath
- } else {
- notepad $configPath
- }
- }
- <#
- .SYNOPSIS
- Shows concise Git status for the current repository.
- #>
- function Get-GitShortStatus {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git status --short --branch @Arguments
- }
- <#
- .SYNOPSIS
- Stages files for commit.
- #>
- function Add-GitItem {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git add @Arguments
- }
- <#
- .SYNOPSIS
- Shows the current Git diff.
- #>
- function Get-GitDiff {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git diff @Arguments
- }
- <#
- .SYNOPSIS
- Shows the staged Git diff.
- #>
- function Get-GitCachedDiff {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git diff --cached @Arguments
- }
- <#
- .SYNOPSIS
- Creates a Git commit.
- #>
- function Invoke-GitCommit {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git commit @Arguments
- }
- <#
- .SYNOPSIS
- Shows a compact decorated Git log for the current repository.
- #>
- function Get-GitOneLineLog {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git log --oneline --graph --decorate -12 @Arguments
- }
- <#
- .SYNOPSIS
- Shows a commit or object with summary statistics.
- #>
- function Get-GitShow {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git show --stat @Arguments
- }
- <#
- .SYNOPSIS
- Shows local branches with verbose tracking information.
- #>
- function Get-GitBranchList {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git branch -vv @Arguments
- }
- <#
- .SYNOPSIS
- Switches branches.
- #>
- function Switch-GitBranch {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git switch @Arguments
- }
- <#
- .SYNOPSIS
- Creates and switches to a new branch.
- #>
- function New-GitBranchSwitch {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git switch -c @Arguments
- }
- <#
- .SYNOPSIS
- Restores files in the working tree or index.
- #>
- function Restore-GitItem {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git restore @Arguments
- }
- <#
- .SYNOPSIS
- Shows line-by-line authorship for a file.
- #>
- function Get-GitBlame {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git blame @Arguments
- }
- <#
- .SYNOPSIS
- Lists tracked files.
- #>
- function Get-GitTrackedFiles {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git ls-files @Arguments
- }
- <#
- .SYNOPSIS
- Fetches updates from the remote.
- #>
- function Invoke-GitFetch {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git fetch @Arguments
- }
- <#
- .SYNOPSIS
- Pulls updates with fast-forward only.
- #>
- function Invoke-GitPull {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git pull --ff-only @Arguments
- }
- <#
- .SYNOPSIS
- Pushes commits to the remote.
- #>
- function Invoke-GitPush {
- [CmdletBinding()]
- param(
- [Parameter(ValueFromRemainingArguments = $true)]
- [string[]]$Arguments
- )
- & git push @Arguments
- }
- <#
- .SYNOPSIS
- Shows a short reference for custom Git aliases.
- #>
- function Show-GitAliasReference {
- [CmdletBinding()]
- param()
- @(
- 'ga git add'
- 'gst git status --short --branch'
- 'gd git diff'
- 'gdc git diff --cached'
- 'glg git log --oneline --graph --decorate -12'
- 'gcmt git commit'
- 'gsh git show --stat'
- 'gbr git branch -vv'
- 'gsw git switch'
- 'gcb git switch -c'
- 'grs git restore'
- 'gbl git blame'
- 'gls git ls-files'
- 'gft git fetch'
- 'gpl git pull --ff-only'
- 'gpu git push'
- ) | ForEach-Object { Write-Host $_ }
- }
- # Aliases for convenience
- ### History and profile
- Set-Alias -Name rh -Value Invoke-HistoryCommand -Description "Search unique history and re-run selected command"
- Set-Alias -Name rhd -Value Remove-PSReadLineHistoryEntry -Description "Delete PSReadLine history by line number"
- Set-Alias -Name eprof -Value Edit-Profile -Description "Open the current PowerShell profile"
- Set-Alias -Name mkcd -Value New-AndEnterDirectory -Description "Create a directory and enter it"
- ### Codex
- Set-Alias -Name croot -Value Enter-CodexWorkspace -Description "Change to C:\Users\J2897\Codex"
- Set-Alias -Name cdx -Value Start-CodexWorkspace -Description "Launch Codex in C:\Users\J2897\Codex"
- Set-Alias -Name cdxs -Value Start-CodexWorkspaceSearch -Description "Launch Codex in C:\Users\J2897\Codex with live web search"
- Set-Alias -Name cdxr -Value Resume-CodexWorkspace -Description "Resume the latest Codex session in C:\Users\J2897\Codex"
- Set-Alias -Name ecodex -Value Edit-CodexConfig -Description "Open ~/.codex/config.toml"
- ### Git
- Set-Alias -Name ga -Value Add-GitItem -Description "Stage files with Git add"
- Set-Alias -Name gst -Value Get-GitShortStatus -Description "Show short Git status with branch"
- Set-Alias -Name gd -Value Get-GitDiff -Description "Show Git diff"
- Set-Alias -Name gdc -Value Get-GitCachedDiff -Description "Show staged Git diff"
- Set-Alias -Name glg -Value Get-GitOneLineLog -Description "Show a compact decorated Git log"
- Set-Alias -Name gcmt -Value Invoke-GitCommit -Description "Create a Git commit"
- Set-Alias -Name gsh -Value Get-GitShow -Description "Show commit details with stats"
- Set-Alias -Name gbr -Value Get-GitBranchList -Description "Show branches with tracking info"
- Set-Alias -Name gsw -Value Switch-GitBranch -Description "Switch branches"
- Set-Alias -Name gcb -Value New-GitBranchSwitch -Description "Create and switch to a new branch"
- Set-Alias -Name grs -Value Restore-GitItem -Description "Restore files with Git restore"
- Set-Alias -Name gbl -Value Get-GitBlame -Description "Show Git blame for a file"
- Set-Alias -Name gls -Value Get-GitTrackedFiles -Description "List tracked Git files"
- Set-Alias -Name gft -Value Invoke-GitFetch -Description "Fetch from remote"
- Set-Alias -Name gpl -Value Invoke-GitPull -Description "Pull with fast-forward only"
- Set-Alias -Name gpu -Value Invoke-GitPush -Description "Push to remote"
- Set-Alias -Name gref -Value Show-GitAliasReference -Description "Show custom Git alias reference"
Add Comment
Please, Sign In to add comment