Skip to content

Instantly share code, notes, and snippets.

@emilwojcik93
Last active July 11, 2025 11:56
Show Gist options
  • Save emilwojcik93/cd5a85621b572dbc3fcc258c60f604bc to your computer and use it in GitHub Desktop.
Save emilwojcik93/cd5a85621b572dbc3fcc258c60f604bc to your computer and use it in GitHub Desktop.
Auto-find & add executables to PATH. Prioritizes WinGet locations, falls back to common Windows dirs. Handles duplicates, force override. No admin.
<#
.SYNOPSIS
WinGet Executable PATH Manager - Intelligent executable discovery and PATH configuration for Windows
.DESCRIPTION
This comprehensive PowerShell script provides automated executable discovery and PATH management
with intelligent priority-based searching. It systematically searches through WinGet registry entries,
WinGet filesystem locations, and common Windows installation directories to locate executables,
then manages Windows PATH entries with sophisticated conflict resolution and force override capabilities.
The script operates without administrative privileges by modifying only the User PATH environment
variable, making it safe for standard user accounts while providing immediate session updates.
KEY FEATURES:
============
• Priority-based executable search starting with WinGet-managed applications
• Comprehensive fallback to standard Windows installation directories
• Advanced PATH/alias existence validation with manual verification
• Intelligent PATH management with duplicate detection and removal
• Force override capability for repairing broken or outdated PATH entries
• Real-time session environment refresh for immediate command availability
• Progress reporting with detailed status updates during searches
• Extensive verbose logging for troubleshooting and debugging
• Non-administrative operation (modifies User PATH only)
• Modular function design for programmatic usage
SEARCH PRIORITY ORDER:
=====================
1. WinGet Registry Entries:
- TargetFullPath (direct executable paths)
- InstallLocation (package directories)
- Recursive subdirectory searches
2. WinGet Filesystem Locations:
- %LOCALAPPDATA%\Microsoft\WinGet\Links (symlinks)
- %LOCALAPPDATA%\Microsoft\WinGet\Packages (package cache)
3. Common Windows Directories:
- %LOCALAPPDATA%\Programs
- %ProgramFiles% and %ProgramFiles(x86)%
- %USERPROFILE%\AppData\Local\Programs
- Package manager directories (Scoop, Chocolatey)
- System directories (%SYSTEMROOT%\System32, %SYSTEMROOT%)
SUPPORTED PACKAGE MANAGERS:
===========================
• WinGet (Microsoft's official package manager)
• Scoop (user-level package manager)
• Chocolatey (community package manager)
• Manual installations in standard directories
SAFETY FEATURES:
================
• Non-destructive PATH modifications (User scope only)
• Duplicate entry detection and prevention
• Existing entry validation before modification
• Force override with explicit user consent
• Comprehensive error handling and graceful degradation
• Session-only environment updates with persistent changes
.PARAMETER ExeName
Specifies the name of the executable file to locate and configure in PATH.
Must include the file extension (e.g., "docker.exe", "git.exe", "python.exe").
The script will search for this exact filename across all configured locations,
starting with WinGet registry entries and falling back to common directories.
.PARAMETER Force
Forces the overwrite of existing PATH entries even if the executable is already
available as a command, alias, or PATH entry. This is useful for:
• Repairing broken PATH entries that point to non-existent locations
• Updating PATH to point to newer versions of software
• Resolving conflicts between multiple installations
• Ensuring WinGet-managed versions take priority over other installations
.PARAMETER Verbose
Enables comprehensive verbose output for detailed logging and troubleshooting.
Provides information about:
• Search progress through each directory
• Registry query results and matches
• PATH analysis and modification decisions
• Error details and access permission issues
• Performance metrics and timing information
.OUTPUTS
System.Collections.Hashtable
Returns a hashtable containing operation results with the following properties:
• Success (Boolean): Whether the operation completed successfully
• Action (String): Description of the action taken
• ExecutablePath (String): Full path to the located executable
• DirectoryPath (String): Directory path added to PATH (if applicable)
• AddedToPath (Boolean): Whether a new PATH entry was created
• Source (String): Location source (WinGet-Registry, WinGet-FileSystem, Common-Location)
• SymlinkPath (String): WinGet symlink path if available
.NOTES
File Name : Find-ExecutableAndSetPath.ps1
Author : GitHub Copilot Assistant
Prerequisite : PowerShell 5.1 or later
Copyright : Free to use and modify
REQUIREMENTS:
• Windows 10/11 or Windows Server 2016+
• PowerShell 5.1 or PowerShell 7+
• Standard user account (no administrative privileges required)
• WinGet installed (optional but recommended for best results)
REGISTRY ACCESS:
The script reads from HKEY_CURRENT_USER registry hive only, which does not
require administrative privileges. It specifically queries:
• HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*
ENVIRONMENT MODIFICATIONS:
• Modifies User PATH environment variable only (not System PATH)
• Changes are persistent across sessions
• Immediate effect in current PowerShell session
• New terminal windows will inherit the updated PATH
.LINK
https://github.com/microsoft/winget-cli
.LINK
https://docs.microsoft.com/en-us/windows/package-manager/
.EXAMPLE
.\Find-ExecutableAndSetPath.ps1 -ExeName "docker.exe"
Searches for docker.exe starting with WinGet locations, then common directories.
If found, adds the containing directory to the User PATH environment variable.
Provides standard output with success/failure status.
.EXAMPLE
.\Find-ExecutableAndSetPath.ps1 -ExeName "git.exe" -Verbose
Performs the same search for git.exe but with comprehensive verbose logging.
Shows detailed information about each search location, registry queries,
and PATH modification decisions.
.EXAMPLE
.\Find-ExecutableAndSetPath.ps1 -ExeName "python.exe" -Force
Forces the addition of python.exe to PATH even if it's already available
as a command. Useful for ensuring the WinGet-managed version takes priority
over other installations like Microsoft Store Python.
.EXAMPLE
Set-ExecutableInPath -ExeName "node.exe" -Force -ShowProgress $true
Uses the script as a module to configure node.exe with progress reporting
and force override enabled. Returns a detailed result object for
programmatic usage.
.EXAMPLE
Find-ExecutableLocation -ExeName "code.exe" -ShowProgress $false
Performs only the search operation without modifying PATH.
Returns location information for Visual Studio Code executable
without progress bar display.
.EXAMPLE
Test-ExecutableInPath -ExeName "docker.exe"
Checks if docker.exe is currently available as a command, alias, or PATH entry
without performing any modifications. Returns detailed availability status.
#>
param(
[Parameter(Mandatory=$false)]
[string]$ExeName,
[switch]$Force
)
# Function 1: Find executable in WinGet and common locations
function Find-ExecutableLocation {
param (
[Parameter(Mandatory=$true)]
[string]$ExeName,
[switch]$ShowProgress = $true
)
# Define search locations in priority order
$wingetLocations = @(
"$env:LOCALAPPDATA\Microsoft\WinGet\Links",
"$env:LOCALAPPDATA\Microsoft\WinGet\Packages"
)
$commonLocations = @(
"$env:LOCALAPPDATA\Programs",
"$env:ProgramFiles",
"${env:ProgramFiles(x86)}",
"$env:USERPROFILE\AppData\Local\Programs",
"$env:USERPROFILE\scoop\apps",
"$env:ChocolateyInstall\lib",
"$env:LOCALAPPDATA\Microsoft\WindowsApps",
"$env:SYSTEMROOT\System32",
"$env:SYSTEMROOT"
)
$allLocations = $wingetLocations + $commonLocations
$totalLocations = $allLocations.Count
$currentLocation = 0
Write-Verbose "Starting search for $ExeName in $totalLocations locations"
# First check WinGet registry for direct paths
Write-Verbose "Checking WinGet registry entries..."
if ($ShowProgress) {
Write-Progress -Activity "Searching for $ExeName" -Status "Checking WinGet registry" -PercentComplete 0
}
try {
$wingetPackages = Get-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Where-Object { $_.WinGetPackageIdentifier }
foreach ($package in $wingetPackages) {
# Check TargetFullPath first (direct executable path)
if ($package.TargetFullPath -and $package.TargetFullPath.EndsWith($ExeName)) {
Write-Verbose "Found in WinGet registry TargetFullPath: $($package.TargetFullPath)"
if ($ShowProgress) { Write-Progress -Activity "Searching for $ExeName" -Completed }
return @{
ExecutablePath = $package.TargetFullPath
DirectoryPath = Split-Path $package.TargetFullPath -Parent
Source = "WinGet-Registry-Target"
SymlinkPath = $package.SymlinkFullPath
}
}
# Check InstallLocation
if ($package.InstallLocation -and (Test-Path $package.InstallLocation)) {
$exePath = Join-Path $package.InstallLocation $ExeName
if (Test-Path $exePath) {
Write-Verbose "Found in WinGet registry InstallLocation: $exePath"
if ($ShowProgress) { Write-Progress -Activity "Searching for $ExeName" -Completed }
return @{
ExecutablePath = $exePath
DirectoryPath = $package.InstallLocation
Source = "WinGet-Registry-Install"
SymlinkPath = $package.SymlinkFullPath
}
}
# Search subdirectories in install location
$foundExe = Get-ChildItem -Path $package.InstallLocation -Filter $ExeName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
if ($foundExe) {
Write-Verbose "Found in WinGet registry subdirectory: $($foundExe.FullName)"
if ($ShowProgress) { Write-Progress -Activity "Searching for $ExeName" -Completed }
return @{
ExecutablePath = $foundExe.FullName
DirectoryPath = $foundExe.DirectoryName
Source = "WinGet-Registry-Subdir"
SymlinkPath = $package.SymlinkFullPath
}
}
}
}
}
catch {
Write-Verbose "Error checking WinGet registry: $($_.Exception.Message)"
}
# Search in file system locations
foreach ($location in $allLocations) {
$currentLocation++
$percentComplete = [math]::Round(($currentLocation / $totalLocations) * 100)
if (-not (Test-Path $location -ErrorAction SilentlyContinue)) {
Write-Verbose "Skipping non-existent location: $location"
continue
}
$locationSource = if ($location -in $wingetLocations) { "WinGet-FileSystem" } else { "Common-Location" }
$status = "Searching in: $location"
if ($ShowProgress) {
Write-Progress -Activity "Searching for $ExeName" -Status $status -PercentComplete $percentComplete
}
Write-Verbose "Searching in: $location"
try {
# Direct path check first (faster)
$directPath = Join-Path $location $ExeName
if (Test-Path $directPath) {
Write-Verbose "Found direct path: $directPath"
if ($ShowProgress) { Write-Progress -Activity "Searching for $ExeName" -Completed }
return @{
ExecutablePath = $directPath
DirectoryPath = $location
Source = $locationSource
SymlinkPath = $null
}
}
# Recursive search
$foundExe = Get-ChildItem -Path $location -Filter $ExeName -Recurse -ErrorAction Stop | Select-Object -First 1
if ($foundExe) {
Write-Verbose "Found recursive: $($foundExe.FullName)"
if ($ShowProgress) { Write-Progress -Activity "Searching for $ExeName" -Completed }
return @{
ExecutablePath = $foundExe.FullName
DirectoryPath = $foundExe.DirectoryName
Source = $locationSource
SymlinkPath = $null
}
}
}
catch {
Write-Verbose "Access denied or error in $location`: $($_.Exception.Message)"
}
}
if ($ShowProgress) { Write-Progress -Activity "Searching for $ExeName" -Completed }
Write-Verbose "$ExeName not found in any location"
return $null
}
# Function 2: Check if executable exists in PATH or as alias
function Test-ExecutableInPath {
param (
[Parameter(Mandatory=$true)]
[string]$ExeName
)
$result = @{
ExistsInPath = $false
ExistsAsAlias = $false
ExistsAsCommand = $false
PathLocation = $null
AliasDefinition = $null
WorkingPath = $null
}
Write-Verbose "Checking if $ExeName exists in PATH or as alias..."
# Check if it's available as a command (which includes PATH and aliases)
$command = Get-Command $ExeName -ErrorAction SilentlyContinue
if ($command) {
$result.ExistsAsCommand = $true
$result.WorkingPath = $command.Source
switch ($command.CommandType) {
'Application' {
$result.ExistsInPath = $true
$result.PathLocation = $command.Source
Write-Verbose "$ExeName found in PATH: $($command.Source)"
}
'Alias' {
$result.ExistsAsAlias = $true
$result.AliasDefinition = $command.Definition
Write-Verbose "$ExeName found as alias: $($command.Definition)"
}
default {
Write-Verbose "$ExeName found as $($command.CommandType): $($command.Source)"
}
}
}
# Double-check PATH manually
if (-not $result.ExistsInPath) {
$pathDirs = $env:Path -split ';' | Where-Object { $_ -and (Test-Path $_ -ErrorAction SilentlyContinue) }
foreach ($dir in $pathDirs) {
$fullPath = Join-Path $dir $ExeName
if (Test-Path $fullPath -ErrorAction SilentlyContinue) {
$result.ExistsInPath = $true
$result.PathLocation = $fullPath
Write-Verbose "$ExeName found manually in PATH: $fullPath"
break
}
}
}
return $result
}
# Function 3: Add directory to PATH
function Add-DirectoryToPath {
param (
[Parameter(Mandatory=$true)]
[string]$DirectoryPath,
[switch]$Force
)
Write-Verbose "Adding directory to PATH: $DirectoryPath"
# Get current user PATH
$userPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
$pathDirs = $userPath -split ';' | Where-Object { $_ }
# Check if directory already exists in PATH
$existsInPath = $pathDirs | Where-Object { $_.TrimEnd('\') -eq $DirectoryPath.TrimEnd('\') }
if ($existsInPath -and -not $Force) {
Write-Verbose "Directory already exists in PATH"
return @{
Added = $false
Reason = "Already exists in PATH"
UpdatedPath = $userPath
}
}
# Remove existing entry if Force is used
if ($existsInPath -and $Force) {
Write-Verbose "Force flag used - removing existing PATH entry"
$pathDirs = $pathDirs | Where-Object { $_.TrimEnd('\') -ne $DirectoryPath.TrimEnd('\') }
}
# Add new directory
$newPathDirs = $pathDirs + $DirectoryPath
$newPath = $newPathDirs -join ';'
# Set environment variable
[System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::User)
# Update current session
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) + ";" + $newPath
Write-Verbose "Successfully added to PATH: $DirectoryPath"
return @{
Added = $true
Reason = if ($Force) { "Force added" } else { "Added normally" }
UpdatedPath = $newPath
}
}
# Function 4: Main function to set executable in PATH
function Set-ExecutableInPath {
param (
[Parameter(Mandatory=$true)]
[string]$ExeName,
[switch]$Force,
[switch]$ShowProgress = $true
)
Write-Host "Processing executable: $ExeName" -ForegroundColor Cyan
# Step 1: Check if executable already works
Write-Verbose "Step 1: Checking current availability..."
$pathCheck = Test-ExecutableInPath -ExeName $ExeName
if ($pathCheck.ExistsAsCommand -and -not $Force) {
Write-Host "[OK] $ExeName is already available" -ForegroundColor Green
if ($pathCheck.ExistsInPath) {
Write-Host " Location: $($pathCheck.PathLocation)" -ForegroundColor Gray
} elseif ($pathCheck.ExistsAsAlias) {
Write-Host " Alias: $($pathCheck.AliasDefinition)" -ForegroundColor Gray
}
return @{
Success = $true
Action = "Already available"
ExecutablePath = $pathCheck.WorkingPath
AddedToPath = $false
}
}
# Step 2: Find executable location
Write-Verbose "Step 2: Searching for executable..."
$location = Find-ExecutableLocation -ExeName $ExeName -ShowProgress:$ShowProgress
if (-not $location) {
Write-Host "[ERROR] $ExeName not found in any location" -ForegroundColor Red
return @{
Success = $false
Action = "Not found"
ExecutablePath = $null
AddedToPath = $false
}
}
Write-Host "[OK] Found $ExeName" -ForegroundColor Green
Write-Host " Location: $($location.ExecutablePath)" -ForegroundColor Gray
Write-Host " Source: $($location.Source)" -ForegroundColor Gray
# Step 3: Add to PATH if needed
Write-Verbose "Step 3: Adding directory to PATH..."
$pathResult = Add-DirectoryToPath -DirectoryPath $location.DirectoryPath -Force:$Force
if ($pathResult.Added) {
Write-Host "[OK] Added to PATH: $($location.DirectoryPath)" -ForegroundColor Green
} else {
Write-Host "[INFO] PATH not modified: $($pathResult.Reason)" -ForegroundColor Yellow
}
return @{
Success = $true
Action = if ($pathResult.Added) { "Found and added to PATH" } else { "Found but not added" }
ExecutablePath = $location.ExecutablePath
DirectoryPath = $location.DirectoryPath
AddedToPath = $pathResult.Added
Source = $location.Source
SymlinkPath = $location.SymlinkPath
}
}
# Function 5: Refresh environment variables
function Update-SessionEnvironment {
Write-Verbose "Refreshing environment variables for current session..."
$machinePath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine)
$userPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
$env:Path = "$machinePath;$userPath"
Write-Host "[OK] Environment variables refreshed" -ForegroundColor Green
}
# Main execution logic
if ($ExeName) {
$result = Set-ExecutableInPath -ExeName $ExeName -Force:$Force -ShowProgress:$true
if ($result.Success) {
Write-Host "`nSummary:" -ForegroundColor Cyan
Write-Host " Action: $($result.Action)" -ForegroundColor White
Write-Host " Executable: $($result.ExecutablePath)" -ForegroundColor White
if ($result.AddedToPath) {
Write-Host " Added to PATH: $($result.DirectoryPath)" -ForegroundColor White
Write-Host "`n[INFO] You may need to restart your terminal for PATH changes to take effect" -ForegroundColor Yellow
}
}
Update-SessionEnvironment
} else {
Write-Host "WinGet Executable PATH Manager" -ForegroundColor Cyan
Write-Host "Usage examples:" -ForegroundColor White
Write-Host " .\Find-ExecutableAndSetPath.ps1 -ExeName 'docker.exe' -Verbose" -ForegroundColor Gray
Write-Host " Set-ExecutableInPath -ExeName 'git.exe' -Force" -ForegroundColor Gray
Write-Host " Find-ExecutableLocation -ExeName 'python.exe'" -ForegroundColor Gray
Write-Host " Test-ExecutableInPath -ExeName 'node.exe'" -ForegroundColor Gray
}
@emilwojcik93
Copy link
Author

Find-ExecutableAndSetPath.ps1

This PowerShell script intelligently finds and configures executables in Windows PATH with priority-based searching. It starts with WinGet-managed applications and falls back to common Windows installation directories, automatically managing PATH entries without requiring administrative privileges.

Usage

.\Find-ExecutableAndSetPath.ps1 [options]

Options

  • -ExeName <String>: The name of the executable file to locate and configure in PATH. Must include file extension (e.g., "docker.exe", "git.exe", "python.exe").
  • -Force: Forces overwrite of existing PATH entries even if the executable is already available. Useful for repairing broken PATH entries or ensuring WinGet versions take priority.
  • -Verbose: Enables comprehensive verbose output for detailed logging and troubleshooting.

Running the Script from the Internet:

Use Invoke-RestMethod to download and execute the script. Here is how you can do it:

# Using Invoke-RestMethod
irm https://gist.githubusercontent.com/emilwojcik93/cd5a85621b572dbc3fcc258c60f604bc/raw/Find-ExecutableAndSetPath.ps1 | iex

Note

If it doesn't work, then try to Set-ExecutionPolicy via PowerShell (Admin)

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force; irm https://gist.githubusercontent.com/emilwojcik93/cd5a85621b572dbc3fcc258c60f604bc/raw/Find-ExecutableAndSetPath.ps1 | iex

Note

To execute the script from the Internet with additional parameters, please run

&([ScriptBlock]::Create((irm https://gist.githubusercontent.com/emilwojcik93/cd5a85621b572dbc3fcc258c60f604bc/raw/Find-ExecutableAndSetPath.ps1))) -ExeName "docker.exe" -Verbose

Example of issue

PS > docker --version
docker : The term 'docker' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ docker --version
+ ~~~~~~
    + CategoryInfo          : ObjectNotFound: (docker:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
PS C:\Users\UserName> winget install Docker.DockerCLI
Found an existing package already installed. Trying to upgrade the installed package...
Found Docker CLI [Docker.DockerCLI] Version 28.3.2
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://download.docker.com/win/static/stable/x86_64/docker-28.3.2.zip
  ██████████████████████████████  41.4 MB / 41.4 MB
Successfully verified installer hash
Extracting archive...
Successfully extracted archive
Starting package install...
Command line alias added: "docker"
Command line alias added: "dockerd"
Successfully installed
PS C:\Users\UserName> where.exe docker
INFO: Could not find files for the given pattern(s).

Example of execution

PS > .\Find-ExecutableAndSetPath.ps1 -ExeName "docker.exe"
Processing executable: docker.exe
[OK] docker.exe is already available
  Location: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker\docker.exe

Summary:
  Action: Already available
  Executable: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker\docker.exe
[OK] Environment variables refreshed

Example of execution with verbose output and force flag

PS > .\Find-ExecutableAndSetPath.ps1 -ExeName "docker.exe" -Verbose -Force
Processing executable: docker.exe
VERBOSE: Step 1: Checking current availability...
VERBOSE: Checking if docker.exe exists in PATH or as alias...
VERBOSE: docker.exe found in PATH: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker\docker.exe
VERBOSE: Step 2: Searching for executable...
VERBOSE: Starting search for docker.exe in 11 locations
VERBOSE: Checking WinGet registry entries...
VERBOSE: Found in WinGet registry subdirectory: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker\docker.exe
[OK] Found docker.exe
  Location: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker\docker.exe
  Source: WinGet-Registry-Subdir
VERBOSE: Step 3: Adding directory to PATH...
VERBOSE: Adding directory to PATH: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker
VERBOSE: Force flag used - removing existing PATH entry
VERBOSE: Successfully added to PATH: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker
[OK] Added to PATH: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker

Summary:
  Action: Found and added to PATH
  Executable: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker\docker.exe
  Added to PATH: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages\Docker.DockerCLI_Microsoft.Winget.Source_8wekyb3d8bbwe\docker

[INFO] You may need to restart your terminal for PATH changes to take effect
VERBOSE: Refreshing environment variables for current session...
[OK] Environment variables refreshed

Example of execution for non-existent executable

PS > .\Find-ExecutableAndSetPath.ps1 -ExeName "nonexistent.exe" -Verbose
Processing executable: nonexistent.exe
VERBOSE: Step 1: Checking current availability...
VERBOSE: Checking if nonexistent.exe exists in PATH or as alias...
VERBOSE: Step 2: Searching for executable...
VERBOSE: Starting search for nonexistent.exe in 11 locations
VERBOSE: Checking WinGet registry entries...
VERBOSE: Searching in: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Links
VERBOSE: Searching in: C:\Users\UserName\AppData\Local\Microsoft\WinGet\Packages
VERBOSE: Searching in: C:\Users\UserName\AppData\Local\Programs
VERBOSE: Searching in: C:\Program Files
VERBOSE: Access denied or error in C:\Program Files: Access to the path 'C:\Program Files\Windows Defender Advanced Threat Protection\Classification\Configuration' is denied.
VERBOSE: Searching in: C:\Program Files (x86)
VERBOSE: Searching in: C:\Users\UserName\AppData\Local\Programs
VERBOSE: Skipping non-existent location: C:\Users\UserName\scoop\apps
VERBOSE: Skipping non-existent location: \lib
VERBOSE: Searching in: C:\Users\UserName\AppData\Local\Microsoft\WindowsApps
VERBOSE: Searching in: C:\Windows\System32
VERBOSE: Access denied or error in C:\Windows\System32: Access to the path 'C:\Windows\System32\Com\dmp' is denied.
VERBOSE: Searching in: C:\Windows
VERBOSE: Access denied or error in C:\Windows: Access to the path 'C:\Windows\appcompat\appraiser' is denied.
VERBOSE: nonexistent.exe not found in any location
[ERROR] nonexistent.exe not found in any location
VERBOSE: Refreshing environment variables for current session...
[OK] Environment variables refreshed

Key Features

Search Priority Order

  1. WinGet Registry Entries: TargetFullPath, InstallLocation, recursive subdirectory searches
  2. WinGet Filesystem Locations: Links directory (symlinks), Packages directory (cache)
  3. Common Windows Directories: Programs folders, package managers (Scoop, Chocolatey), system directories

Safety Features

  • Non-administrative operation: Modifies User PATH only, not System PATH
  • Duplicate entry detection: Prevents PATH pollution
  • Force override capability: Repairs broken or outdated PATH entries
  • Session environment refresh: Immediate availability in current session

Functions

Find-ExecutableLocation

  • Purpose: Searches for executables with intelligent priority-based location discovery.
  • Parameters:
    • ExeName: The executable name to search for
    • ShowProgress: Enable/disable progress bar display
  • Example: $location = Find-ExecutableLocation -ExeName "docker.exe" -ShowProgress $true

Test-ExecutableInPath

  • Purpose: Checks if an executable exists in PATH or as an alias with comprehensive validation.
  • Parameters:
    • ExeName: The executable name to check
  • Example: $pathStatus = Test-ExecutableInPath -ExeName "git.exe"

Add-DirectoryToPath

  • Purpose: Intelligently adds directories to User PATH with duplicate detection and force override.
  • Parameters:
    • DirectoryPath: The directory path to add to PATH
    • Force: Force overwrite existing entries
  • Example: Add-DirectoryToPath -DirectoryPath "C:\Tools\bin" -Force

Set-ExecutableInPath

  • Purpose: Main orchestration function that combines search, validation, and PATH management.
  • Parameters:
    • ExeName: The executable name to configure
    • Force: Force override existing PATH entries
    • ShowProgress: Enable progress reporting
  • Example: Set-ExecutableInPath -ExeName "python.exe" -Force -ShowProgress $true

Update-SessionEnvironment

  • Purpose: Refreshes environment variables for the current PowerShell session.
  • Example: Update-SessionEnvironment

Supported Package Managers

  • WinGet: Microsoft's official package manager (priority search)
  • Scoop: User-level package manager
  • Chocolatey: Community package manager
  • Manual installations: Standard Windows directories

Requirements

  • Windows 10/11 or Windows Server 2016+
  • PowerShell 5.1 or PowerShell 7+
  • Standard user account (no administrative privileges required)
  • WinGet installed (optional but recommended for best results)

Related Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment