Last active
December 9, 2025 21:26
-
-
Save eabase/24af97bf1ae50359648e5588d96bf1c9 to your computer and use it in GitHub Desktop.
Windows System/User PATH variable manager and analyzer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env pwsh | |
| # TAB:4sp + EOL:CRLF | |
| #------------------------------------------------------------------------------ | |
| # Filename : SystemPath.ps1 | |
| # Author : eabase | |
| # Date : 2025-12-09 | |
| # Version : 1.0.2 | |
| # Encoding : UTF-8 | |
| # License : CC-BY-SA-4.0 | |
| #------------------------------------------------------------------------------ | |
| # | |
| # Description | |
| # Get/Set and save/load User & System PATH variables | |
| # | |
| # NOTE | |
| # - The User PATH is appended to the Machine (System) PATH Variable when a session starts. | |
| # - When a process starts, Windows combines the System PATH and User PATH. | |
| # - The System PATH is loaded first, followed by the User PATH. | |
| # - If a program exists in both, the System PATH version takes precedence. | |
| # - The theoretical limit for an environment variable in Windows is 32,767 characters | |
| # - The System PATH variable is often restricted by registry editors, which may truncate values at 2047 characters. | |
| # - The User PATH variable may also be affected by certain tools, such as setx, which limits values to 1023 characters. | |
| # - When starting pwsh.exe from Windows Terminal, 'pwsh.exe' adds it's own | |
| # path ("C:\Program Files\PowerShell\7") to the top of the PATH environment variable. | |
| # - GetEnvironmentVariable always returns the expanded value (no % aliases). | |
| # - To see the original alias form with % signs, you must read the registry entries directly (HKLM for system, HKCU for user). | |
| # | |
| # To Directly Open Windows Settings UI for Environment Variables (from powershell/terminal) | |
| # rundll32 sysdm.cpl,EditEnvironmentVariables | |
| # | |
| # Debug: | |
| # . "C:\Users\xxxx\Documents\PowerShell\Trace-Function.ps1" | |
| # Trace-Function -Script { SystemPath.ps1 -e } -Prefix 'TRACE' | |
| # | |
| #------------------------------------------------------------------------- | |
| # Some Examples: | |
| #------------------------------------------------------------------------- | |
| # .\SystemPath -e # show the extended (Machine) Path alias %XLPATH% | |
| # .\SystemPath -e "C:\NEW\PATH" # add provided Path to the extended (Machine) Path alias in %XLPATH% | |
| # .\SystemPath -g # show the PATH using the Registry (which includes the % aliases) | |
| # .\SystemPath -i .\some_paths.txt # print file content | |
| # .\SystemPath -u -l # print length of User PATH variable | |
| # .\SystemPath -l | |
| # .\SystemPath -p | |
| # .\SystemPath -s | |
| # .\SystemPath -u -d | |
| # .\SystemPath -r -o . # Write raw Machine paths to timestamped file | |
| # .\SystemPath -p -o . # Write line-by-line Machine paths to timestamped file | |
| # ----- WIP ----- | |
| # .\SystemPath -i .\some_paths.txt -w # write file content to SPATH (Machine) | |
| # .\SystemPath -i .\some_paths.txt -w User # write file content to UPATH (User) | |
| # .\SystemPath -i .\some_paths.txt -c # Cleanup paths in file (see notes) | |
| # .\SystemPath -t -o .\spath_reverse_sorted.txt # Write reverse sorted Machine paths to named file | |
| # .\SystemPath -w | |
| # | |
| # Other Examples: | |
| # | |
| # $UPATH = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::User) | |
| # $SPATH = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine) | |
| # $SPATH += ';C:\mybin\mytools' | |
| # [System.Environment]::SetEnvironmentVariable('PATH', $SPATH, [System.EnvironmentVariableTarget]::Machine) | |
| # $SPATH | Measure-Object -Character | |
| # [System.Environment]::SetEnvironmentVariable("Path", $NewPath, $PathType) | |
| # | |
| # Reading PATH's from registry: | |
| # | |
| # # Machine-level PATH (raw, may contain %SystemRoot%) | |
| # $LP = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' | |
| # Get-ItemProperty -Path $LP | Select-Object -ExpandProperty Path | |
| # | |
| # User-level PATH (raw) | |
| # Get-ItemProperty -Path 'HKCU:\Environment' | Select-Object -ExpandProperty Path | |
| # | |
| #------------------------------------------------------------------------- | |
| # | |
| # TODO: | |
| # [ ] Fix line endings and formatting and use: '[Environment]::NewLine' (the platform independent EOL). | |
| # [ ] Fix write confirmation dialog before writing new PATH | |
| # [-] Add removal of pwsh.exe's own top PATH addition (See NOTE below.) | |
| # [ ] Add CLI switch ('-c') to "cleanup" PATH, by: | |
| # - Remove all trailing `\` for each entry | |
| # - Remove duplicates and keep only 1st entry | |
| # [x] Add CLI switch ('-e') to add/extend Extended path alias %ELPATH% | |
| # - Extends PATH with a %XLPATH% (Extenden Long PATH) alias variable | |
| # - Ensure proper handling of displaying %PATH% aliases | |
| # [x] Add CLI switch ('-g') to read and display PATH's from registry (that include the % aliases) | |
| # [x] Create alias to open environment variable settings | |
| # | |
| #------------------------------------------------------------------------------ | |
| param ( | |
| [Alias("i")] [string] $InputFile, # <input-file> | |
| [Alias("o")] [string] $OutputFile, # <output-file> | |
| #[Alias("c")] [switch] $CleanPath, # Cleanup Machine PATH | |
| # using switch + x | |
| [Alias("e")] [switch] $PrintXLPath, # Print %XLPATH% PATH alias content | |
| [Alias("x")] [string] $SetXLPath = '', # Print %XLPATH% PATH alias content | |
| [Alias("g")] [switch] $PrintRegistryPath, # Print Machine/User PATH's from registry | |
| [Alias("l")] [switch] $PrintPathLength, # Print true length of PATH variable | |
| [Alias("p")] [switch] $PrintPathLines, # Print PATH Line-by-line | |
| [Alias("r")] [switch] $PrintRawPath, # Print "Raw" PATH variable | |
| [Alias("s")] [switch] $SortPaths, # Print PATH lexically sorted | |
| [Alias("t")] [switch] $SortPathsReverse, # Print PATH lexically sorted in reverse | |
| [Alias("w")] [switch] $WriteToSystemPath, # WRITE !! | |
| [Alias("u")] [switch] $UseUserPath, # [User | Machine] PATH | |
| [Alias("d")] [switch] $CheckForDuplicates # Print duplicated paths | |
| # This doesn't work for unknown reason: | |
| #[Alias("o")][AllowNull()][AllowEmptyString()][string] $OutputFile, # <output-file> | |
| ) | |
| #-------------------------------------- | |
| # Constants | |
| #-------------------------------------- | |
| $MAX_VARL = 32767 # Maximum environment variable length | |
| $MAX_SPATH = 2047 # Changing the path variable via the Windows UI will no longer work | |
| $MAX_SETXL = 1023 # setx will no longer work | |
| #------------------------------------------------------------------------------ | |
| # Helper Function | |
| #------------------------------------------------------------------------------ | |
| # Print CLI option strings | |
| function popt() { | |
| param([string] $opt, [string] $txt) | |
| Write-Host -f White " -$opt" -Non; Write-Host -f Gray "`t $txt" | |
| } | |
| function usage() { | |
| #$sfp = Split-Path -Path $PSCommandPath -Leaf # Script filename + extension | |
| $sfp = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath) # Script filename | |
| #Write-Error "No parameters passed" | |
| Write-Host -f White "`nUsage:`n" | |
| Write-Host -f DarkYellow "$sfp [options] [-i <input-filename>] [-o <output-filename>]`n" | |
| Write-Host -f DarkGray "Command Line [options]:" | |
| popt 'e' 'Show the extended (Machine) Path alias %XLPATH%' | |
| popt 'g' 'Read and display PATHs from registry (that include the % aliases)' | |
| popt 'i' 'Specify an <input-file> - Expecting line-by-line with or without ";"s' | |
| popt 'o' 'Specify an <output-file> - Writing it line-by-line without ";"s' | |
| popt 'd' 'Print duplicated paths' | |
| #popt 'k' 'Use raw format with semicolons in saved files.' | |
| popt 'l' 'Print true length of PATH variable' | |
| popt 'p' 'Print PATH Line-by-line' | |
| popt 'r' 'Print "Raw" PATH variable' | |
| popt 's' 'Print PATH lexically sorted' | |
| popt 't' 'Print PATH lexically sorted in reverse' | |
| popt 'u' 'Select User PATH variable (default: Machine)' | |
| popt 'x' 'Add provided path to the extended (Machine) Path alias %XLPATH%' | |
| Write-Host -f DarkGray "`n--------------------------------------------------------------------------" | |
| popt 'c' '(WIP) Clean PATH by removing duplicates (keeping 1st) and trailing "\"' | |
| popt 'w' '(WIP) Write to specified Windows PATH variable (default: Machine)' | |
| Write-Host -f DarkGray "`n--------------------------------------------------------------------------" | |
| Write-Host -f Green "NOTE:" | |
| Write-Host -f DarkGray "- The Maximum OS environment variable length is: $MAX_VARL." | |
| Write-Host -f DarkGray "- The Maximum Windows UI editable PATH variable length is: $MAX_SPATH." | |
| Write-Host -f DarkGray "- The Maximum CMD (setx) editable PATH variable length is: $MAX_SETXL." | |
| Write-Host -f DarkGray "- Files are saved line-by-line without semicolons (;) for easy editing." | |
| Write-Host -f DarkGray "- Files are read line-by-line with or without semicolons (;)." | |
| Write-Host -f DarkGray "- If you specify a dot ('.') for the filename with the -o option," | |
| Write-Host -f DarkGray " you automatically get a time stamped filename in the format:" | |
| Write-Host -f DarkGray " SPATH_2025_0601_1731.txt" | |
| Write-Host -f DarkGray "- You can open the Windows PATH settings directly from powershell with:" | |
| Write-Host -f Gray " rundll32 sysdm.cpl,EditEnvironmentVariables" | |
| Write-Host -f DarkGray "- If you dot-source this script, you can also use the 'EnvEdit' alias." | |
| Write-Host -f DarkGray "- You need to run from an Admin shell to be able to edit the Machine PATH's." | |
| Write-Host -f DarkGray "--------------------------------------------------------------------------`n" | |
| exit 0 | |
| } | |
| function check_if_admin (){ | |
| # Check if running script as Admin | |
| $isAdmin = [Security.Principal.WindowsIdentity]::GetCurrent().groups -match 'S-1-5-32-544' | |
| if (-not $isAdmin) { | |
| Write-Host -f DarkRed "`nRun script as Admin if you need to write to system Machine PATH's!" | |
| } | |
| } | |
| # Show raw Machine and User paths from registry | |
| # - These paths contain explicit % aliases. | |
| function dump_paths_from_registry { | |
| Write-Host -f DarkYellow "`nRegistry Machine PATH:" | |
| # Machine-level PATH (raw, may contain %SystemRoot%) | |
| $LP = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' | |
| $RSPATH = Get-ItemProperty -Path $LP | Select-Object -ExpandProperty Path | |
| Write-Host -f DarkGray "$RSPATH" | |
| Write-Host -f DarkYellow "`nRegistry User PATH:" | |
| # User-level PATH (raw) | |
| $RUPATH = Get-ItemProperty -Path 'HKCU:\Environment' | Select-Object -ExpandProperty Path | |
| Write-Host -f DarkGray "$RUPATH`n" | |
| } | |
| #------------------------------------------------ | |
| # Add alias to Environment Variable Settings | |
| #------------------------------------------------ | |
| # In order for functions to be aliased from a script, | |
| # the script need to be dot sourced: ". .\SystemPath.ps1" | |
| # If not, you need to convert it to a module (*.psm1), or use a wrapper. | |
| #------------------------------------------------ | |
| #if ($MyInvocation.InvocationName -ne '.') { | |
| # Write-Warning "This script should be dot-sourced: . $($MyInvocation.MyCommand.Path)" | |
| #} | |
| function open_env_settings { | |
| Write-Host -f DarkYellow "Opening Windows settings for editing Environment variables..." | |
| Write-Host -f DarkGray "You must run from an Admin shell to edit System/Machine variables.`n" | |
| #rundll32 sysdm.cpl,EditEnvironmentVariables | |
| Start-Process rundll32.exe -ArgumentList 'sysdm.cpl,EditEnvironmentVariables' | |
| } | |
| try { Remove-Alias 'EnvEdit' -Force -ErrorAction 0; } catch {} | |
| Set-Alias -Name 'EnvEdit' -Value open_env_settings -Description 'Opening Windows settings for Environment variables' -Scope Global -Option AllScope | |
| #------------------------------------------------------------------------------ | |
| # Main | |
| #------------------------------------------------------------------------------ | |
| if ( $PSBoundParameters.Values.Count -eq 0 ) { | |
| usage | |
| } | |
| #-------------------------------------- | |
| # Check User vs. System PATH | |
| #-------------------------------------- | |
| # [-u] Determine whether to use System or User PATH | |
| if ($UseUserPath) { $PathType = "User" } else { $PathType = "Machine" } | |
| # Get the selected PATH variable | |
| $SystemPath = [System.Environment]::GetEnvironmentVariable("Path", $PathType) -split ";" | |
| #-------------------------------------- | |
| # Handle Options | |
| #-------------------------------------- | |
| # [-g] | |
| if ($PrintRegistryPath) { | |
| dump_paths_from_registry | |
| exit | |
| } | |
| # [-e / -x] | |
| function get_expath () { | |
| $EXP1 = [System.Environment]::GetEnvironmentVariable("EXPATH", 'Machine') | |
| $EXP2 = $EXP1 -split ";" | |
| if ($EXP2) { | |
| Write-Host -f DarkYellow "`nYour current Extended PATH environment alias, %EXPATH% is:" | |
| Write-Host -f DarkGray "$EXP2`n" | |
| } else { | |
| Write-Host -f Red "`nNo EXPATH variable defined.`n" | |
| } | |
| } | |
| function add_expath () { | |
| if ($args.count -eq 1) { | |
| # TODO: Add sanity check | |
| $EX = $args[0] | |
| #Write-Host -f DarkYellow "`nEX:`n$EX`n" | |
| $EXP1 = [System.Environment]::GetEnvironmentVariable("EXPATH", 'Machine') | |
| Write-Host -f DarkYellow "`nAdding the following path to the EXPATH (system) variable:" | |
| Write-Host -f Magenta "$EX" | |
| if ($EXP1) { $EXPath = "${EXP1};${EX}"; } else { $EXPath = "${EX}"; } | |
| Write-Host -f DarkYellow "The new EXPATH will be:" | |
| Write-Host -f DarkGray "$EXPath`n" | |
| #[System.Environment]::SetEnvironmentVariable("EXPATH", $ExPath, 'User') | |
| [System.Environment]::SetEnvironmentVariable("EXPATH", $ExPath, 'Machine') | |
| Start-Sleep 0.5 | |
| Write-Host -f DarkYellow "The new EXPATH is:" | |
| # This might mnot be stable at this point. Do we need to reload/refresh environment? | |
| $NEXP = [System.Environment]::GetEnvironmentVariable("EXPATH", 'Machine') | |
| Write-Host -f DarkGray "$NEXP`n" | |
| #Write-Host -f DarkGray "$env:EXPATH`n" | |
| # Check if EXPATH is present in Machine PATH variable, via Registry | |
| Write-Host -f DarkGreen "[INFO] " -NoN; Write-Host -f Gray "Checking for EXPATH alias in Machine PATH variable..." | |
| $LP = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' | |
| #$RSPATH = Get-ItemProperty -Path $LP | Select-Object -ExpandProperty Path | |
| $RSPATH = Get-ItemPropertyValue -Path $LP -Name 'Path' -EA Stop | |
| if ($RSPATH.Contains('%EXPATH%') ) { | |
| Write-Host -f DarkGreen "Machine PATH already have an EXPATH alias. OK." | |
| exit | |
| } else { | |
| Write-Host -f DarkRed "Machine PATH doesn't have an EXPATH alias. Adding..." | |
| # We must use the Registry here! [?] | |
| # $SPATH = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine) | |
| # $SPATH += ';%EXPATH%' | |
| # [System.Environment]::SetEnvironmentVariable('PATH', $SPATH, [System.EnvironmentVariableTarget]::Machine) | |
| $NSPATH = "$RSPATH;%EXPATH%" | |
| try { | |
| Set-ItemProperty -Path $LP -Name 'Path' -Value "$NSPATH" | |
| Write-Host -f Green "OK`n" | |
| } catch { | |
| Write-Host -f DarkRed "`nWARNING! Error Setting Machine PATH in Registry!" | |
| Write-Host -f Red "Make sure to check your Machine (system) PATH in registry before closing." | |
| Write-Host -f Red "$LP`n" | |
| } | |
| } | |
| } | |
| exit | |
| } | |
| # [-e] | |
| if ($PrintXLPath) { | |
| get_expath | |
| exit | |
| } | |
| # [-x] | |
| if ($SetXLPath) { | |
| check_if_admin | |
| get_expath | |
| add_expath $SetXLPath | |
| } | |
| # [-c] | |
| # [-i] | |
| # If we are reading from an external file: | |
| # - we don't use/load the Windows PATH variable. | |
| # - we assume its a line-by-line file without semicolons (';') | |
| # - we then join the lines with semicolons for storing in local variable for further use. | |
| # TODO: Bug! It interprets path\nano as (\n) NewLine ! | |
| if ($InputFile) { | |
| $InternalPaths = '' | |
| try { | |
| #$FileContent = Get-Content -Encoding UTF8 $InputFile # -Delimiter '\n' ? | |
| $FileContent = Get-Content -Encoding UTF8 $InputFile -Delimiter '\r\n' # maybe [Environment]::NewLine OR '`r`n' ? | |
| } catch { | |
| Write-Host -f Red "`n[ERROR] Could not open file...`n" | |
| Return | |
| } | |
| Write-Host -f DarkYellow "`nRead File Content:" | |
| Write-Host -f DarkGray "$FileContent`n" | |
| #$InternalPaths += $FileContent # -split ";" | |
| #$InternalPaths += $FileContent -split ";" | |
| $InternalPaths += $FileContent -join ";" | |
| } else { | |
| # Internal variable to hold User/System paths | |
| $InternalPaths = $SystemPath | |
| } | |
| # [-l] | |
| # Print true windows registry length of the User|Machine PATH variable. | |
| if($PrintPathLength) { | |
| # PATH Character Counter | |
| # TODO: Use raw path with ";" | |
| $RawPath = [System.Environment]::GetEnvironmentVariable("Path", $PathType) | |
| $PLEN = ($RawPath | Measure-Object -Character).Characters | |
| # Define some messages | |
| $PLD1 = ($PLEN - $MAX_SPATH) # (2047) Windows GUI limit | |
| $PLD2 = ($PLEN - $MAX_SETXL) # (1023) CMD setx limit | |
| $MSG1 = "`nYour $PathType PATH variable length exceeds the maximum allowed value of " # "$MAX_SPATH | $MAX_SETXL by $PLD1 characters" | |
| $MSG2 = "- You will not be able to use 'setx' from command line." | |
| $MSG3 = "- You will not be able to use the Windows Settings GUI to change your PATH variable." | |
| $MSG4 = "- You can still change the Machine PATH from Windows GUI or an Admin Powershell." | |
| $MSG5 = "- You can only change the Machine PATH from an Admin Powershell, using:" | |
| $MSG6 = ' $SPATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine")' | |
| $MSG7 = ' [System.Environment]::SetEnvironmentVariable("Path", $NewPath, "Machine")' | |
| $MSG8 = "- The PATH shown in your terminal shell is the combined System (Machine) + User PATH's" | |
| Write-Host -f DarkYellow "`nYour Current $PathType PATH length is: " -Non; Write-Host -f White "$PLEN" -Non; Write-Host -f DarkYellow " characters." | |
| if ($PathType -eq "Machine") { | |
| if ($PLEN -ge $MAX_SPATH) { | |
| Write-Host -f Red "[WARNING]" -Non; Write-Host -f DarkGray "$MSG1" -Non; | |
| Write-Host -f Red "$MAX_SPATH" -Non; Write-Host -f DarkGray " by " -Non; Write-Host -f Red "$PLD1" -Non; Write-Host -f DarkGray " characters." | |
| Write-Host -f DarkGray "$MSG2`n$MSG3`n$MSG5`n$MSG6`n$MSG7" | |
| Return | |
| } elseif ($PLEN -gt $MAX_SETXL) { | |
| Write-Host -f Red "[WARNING]" -Non; Write-Host -f DarkGray "$MSG1" -Non; | |
| Write-Host -f Red "$MAX_SETXL" -Non; Write-Host -f DarkGray " by " -Non; Write-Host -f Red "$PLD2" -Non; Write-Host -f DarkGray " characters." | |
| Write-Host -f DarkGray "$MSG2`n$MSG4" | |
| } | |
| } elseif ($PathType -eq "User") { | |
| if ($PLEN -gt $MAX_SPATH) { | |
| Write-Host -f Red "[WARNING]" -Non; Write-Host -f DarkGray "$MSG1" -Non; | |
| Write-Host -f Red "$MAX_SPATH" -Non; Write-Host -f DarkGray " by " -Non; Write-Host -f Red "$PLD1" -Non; Write-Host -f DarkGray " characters." | |
| Write-Host -f DarkGray "$MSG2`n$MSG3`n$MSG5`n$MSG7" | |
| Return | |
| } elseif ($PLEN -gt $MAX_SETXL) { | |
| Write-Host -f Red "[WARNING]" -Non; Write-Host -f DarkGray "$MSG1" -Non; | |
| Write-Host -f Red "$MAX_SETXL" -Non; Write-Host -f DarkGray " by " -Non; Write-Host -f Red "$PLD2" -Non; Write-Host -f DarkGray " characters." | |
| Write-Host -f DarkGray "$MSG2`n$MSG4" | |
| } | |
| } | |
| Write-Host -f DarkGray "$MSG8" | |
| return | |
| } | |
| # [-s, -t] | |
| # Print lexically Sorted paths | |
| if ($SortPaths -or $SortPathsReverse) { | |
| if ($SortPathsReverse) { | |
| $SortedPaths = $InternalPaths | Sort-Object -Descending | |
| } else { | |
| $SortedPaths = $InternalPaths | Sort-Object | |
| } | |
| $SortedPaths | ForEach-Object { Write-Output $_ } | |
| # Copy so we can use it | |
| $InternalPaths = $SortedPaths | |
| #return | |
| } | |
| # [-r] | |
| # Print the raw PATH variable in one line (with semicolons ';') | |
| if ($PrintRawPath) { | |
| #Write-Host -f DarkYellow "The InternalPath:`n$InternalPaths`n" | |
| Write-Host "`n" | |
| $InternalPaths -join ";" | |
| Write-Host "`n" | |
| #return | |
| } | |
| # [-p] | |
| # Print the raw PATH variable line-by-line (without semicolons) | |
| if ($PrintPathLines) { | |
| $InternalPaths | ForEach-Object { Write-Output $_ } | |
| #return | |
| } | |
| # [-d] | |
| # Check for duplicate paths and print them | |
| if ($CheckForDuplicates) { | |
| $Duplicates = $InternalPaths | Group-Object | Where-Object { $_.Count -gt 1 } | ForEach-Object { $_.Name } | |
| if ($Duplicates) { | |
| Write-Host -f Red "`n[WARNING]" -Non | |
| Write-Host -f Yellow " Duplicate $PathType paths detected!`n" | |
| $Duplicates | ForEach-Object { Write-Output $_ } | |
| } else { | |
| Write-Host -f Green "`nNo duplicates found in $PathType PATH.`n" | |
| } | |
| return | |
| } | |
| # [-w] | |
| # Write sorted paths to the Machine/System or User PATH variable | |
| # #Write-Host -f DarkGray "The InternalPath:`n$InternalPaths`n" | |
| # Write-Host "`n" | |
| # $InternalPaths -join ";" | |
| if ($WriteToSystemPath) { | |
| check_if_admin | |
| # ToDo: | |
| # - Add "-r" | |
| # - Use try/catch | |
| # - Use [Environment]::NewLine (platform independent EOL) | |
| Write-Host -f DarkYellow "The pending human readable (line-by-line) PATH:`n" | |
| Write-Host -f DarkGray "$InternalPaths" | |
| # Windows is using CRLF (\r\n) for each EOL | |
| #$NewPath = $InternalPaths -replace ("`r`n", ";") | |
| #$NewPath = $InternalPaths -join ";" | |
| # We already joined on ";" in [-i] above | |
| $NewPath = $InternalPaths -join "`n" | |
| Write-Host -f DarkYellow "`nWriting the following raw PATH:" | |
| Write-Host -f DarkGray "`n$NewPath`n" | |
| # TODO: Fix prettier confirmation | |
| $answer = Read-Host "Confirm writing the above to the System (Machine) PATH? (Enter is [Yes])" | |
| if ($answer -in 'N','n') { exit } | |
| [System.Environment]::SetEnvironmentVariable("Path", $NewPath, $PathType) | |
| Write-Host -f DarkYellow "`nUpdated Windows Registry " -Non; Write-Host -f Yellow "$PathType" -Non; Write-Host -f DarkYellow " PATH with above path modification." | |
| Write-Host -f Red "Refresh your environment for new PATH to take effect.`n" | |
| return | |
| } | |
| # [-o] [-r] [-s,-t] | |
| # Write to file if specified | |
| # TODO: More cleanup and testing | |
| if ($OutputFile) { | |
| # Set Default Filename | |
| $PathFilePrefix = 'SPATH' # Default is: Machine (System) Path | |
| if ($PathType -eq 'User') { | |
| $PathFilePrefix = 'UPATH' | |
| } | |
| $DateString = Get-Date -Format "yyyy_MMdd_HHmm" # 2025_0601_1731 | |
| $DefaultFileName = "${PathFilePrefix}_${DateString}.txt" # SPATH_2025_0601_1731.txt | |
| #if ([string]::IsNullOrEmpty($OutputFile)) { | |
| if ($OutputFile -eq '.') { | |
| $OutputFile = $DefaultFileName | |
| } | |
| if ($PrintRawPath) { | |
| # TODO: Use [Environment]::NewLine | |
| #$NewPath = $InternalPaths -replace ("`r`n", ";") | |
| #$InternalPaths = ($InternalPaths -replace ("`r`n", ";")) | |
| $InternalPaths = $InternalPaths -join ";" | |
| $UpdatedPath = $InternalPaths -replace ("`r`n", ";") | |
| } else { | |
| $UpdatedPath = $InternalPaths | |
| } | |
| if ($SortPaths) { | |
| # CHECK: This seem to be already handled | |
| $SortedPaths | Out-File -Encoding UTF8 -FilePath $OutputFile | |
| #Out-File -InputObject $UpdatedPath -Encoding UTF8 -FilePath $OutputFile -NoNewline | |
| } else { | |
| if ($PrintRawPath) { | |
| #$InternalPaths | Out-File -Encoding UTF8 -FilePath $OutputFile | |
| #Out-File -InputObject $InternalPaths -Encoding UTF8 -FilePath $OutputFile | |
| #----------------------------------------------------- | |
| # NOTE: | |
| # ToDo: This doesn't do RAW! It interprets \n as LF !! | |
| #----------------------------------------------------- | |
| Out-File -InputObject $UpdatedPath -Encoding UTF8 -FilePath $OutputFile -NoNewline | |
| } else { | |
| Out-File -InputObject $UpdatedPath -Encoding UTF8 -FilePath $OutputFile | |
| } | |
| } | |
| Write-Host -f DarkYellow "`n$PathType PATH saved to: " -Non; Write-Host -f White "$OutputFile`n" | |
| return | |
| } | |
| #------------------------------------------------------------------------------ | |
| # END | |
| #------------------------------------------------------------------------------ |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Caution
I haven't tested the writing option (
-w) when used together with other options such as (-i, -s, -tetc.)Please make sure to review the code before using.
Tip
If you find any issues or have ideas for improvement, please let me know below.
UPDATES2025-12-09(v1.0.2)-g) for reading of Machine PATH in Registry-e, -x) for handling for adding/using an external Machine%EXPATH%alias inPATH.Remaining bugs:
-w)Don't use this for now!