PATH.psm1
[CmdletBinding()] param() if ($PSVersionTable.PSVersion -lt '6.0') { [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidAssignmentToAutomaticVariable', '', Justification = 'Compatibility with PowerShell 6.0 and newer.' )] $IsWindows = [System.Environment]::OSVersion.Platform -eq 'Win32NT' } $scriptName = 'PATH' Write-Verbose "[$scriptName] - Importing module" #region - From [public] Write-Verbose "[$scriptName] - [public] - Processing folder" #region - From [public] - [Add-EnvironmentPath] Write-Verbose "[$scriptName] - [public] - [Add-EnvironmentPath] - Importing" #Requires -Modules Admin function Add-EnvironmentPath { <# .SYNOPSIS Add a path to the PATH environment variable. .DESCRIPTION Add a path to the PATH environment variable. This command will normalize the path separators. .EXAMPLE Add-EnvironmentPath -Scope CurrentUser -Path 'C:\Program Files\Git\cmd' Add the path 'C:\Program Files\Git\cmd' to the PATH environment variable for the current user. .EXAMPLE Add-EnvironmentPath -Scope AllUsers -Path 'C:\Program Files\Git\cmd' Add the path 'C:\Program Files\Git\cmd' to the PATH environment variable for all users. .EXAMPLE Add-EnvironmentPath -Scope CurrentUser -Path 'C:\Program Files\Git\cmd', 'C:\Program Files\Git\bin' Add the paths 'C:\Program Files\Git\cmd' and 'C:\Program Files\Git\bin' to the PATH environment variable for the current user. .EXAMPLE Add-EnvironmentPath -Scope CurrentUser -Path 'C:\Program Files\Git\cmd', 'C:\Program Files\Git\bin' -Force Add the paths 'C:\Program Files\Git\cmd' and 'C:\Program Files\Git\bin' to the PATH environment variable for the current user. Any invalid paths will be removed. .EXAMPLE 'C:\Program Files\Git\cmd', 'C:\Program Files\Git\bin' | Add-EnvironmentPath -Scope CurrentUser Add the paths 'C:\Program Files\Git\cmd' and 'C:\Program Files\Git\bin' to the PATH environment variable for the current user. #> [CmdletBinding()] param( # The scope of the environment variable. [Parameter()] [ValidateSet('AllUsers', 'CurrentUser')] [string] $Scope = 'CurrentUser', # The path to add to the environment variable. [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )] [ValidateNotNullOrEmpty()] [Alias('FullName')] [string[]] $Path, # Remove any invalid paths. [Parameter()] [switch] $Force ) begin { $separatorChar = [System.IO.Path]::DirectorySeparatorChar $target = if ($Scope -eq 'CurrentUser') { [System.EnvironmentVariableTarget]::User } else { [System.EnvironmentVariableTarget]::Machine if (-not (IsAdmin)) { $errorMessage = @' Administrator rights are required to modify machine PATH. Please run the command again with elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command. '@ throw $errorMessage } } $environmentPath = Get-EnvironmentPath -Scope $Scope -AsArray Write-Verbose "Add PATH - [$target]" } process { foreach ($envPath in $Path) { Write-Verbose "Add PATH - [$target] - [$envPath]" $envPathExists = Test-Path $envPath if ($envPathExists) { Write-Verbose "Add PATH - [$target] - [$envPath] - Path exists - Yes" $envPathObject = Get-Item -Path $envPath -ErrorAction SilentlyContinue if ($envPath -ceq $envPathObject.FullName) { Write-Verbose "Add PATH - [$target] - [$envPath] - Verify path - Ok" } else { $envPath = $envPathObject.FullName Write-Verbose "Add PATH - [$target] - [$envPath] - Verify path - Updated" } } else { if ($Force) { Write-Verbose "Add PATH - [$target] - [$envPath] - Path exists - No - Continuing (Force)" } else { Write-Warning "Add PATH - [$target] - [$envPath] - Path exists - No - Skipping (Use -Force to add)" continue } } Write-Verbose "Add PATH - [$target] - [$envPath] - Normalize path" $envPath = $envPath.Replace('\', $separatorChar) $envPath = $envPath.Replace('/', $separatorChar) $envPath = $envPath.TrimEnd($separatorChar) $environmentPath += $envPath Write-Verbose "Add PATH - [$target] - [$envPath] - Added" } } end { $pathSeparator = [System.IO.Path]::PathSeparator $environmentPath = $environmentPath -join $pathSeparator $environmentPath = $environmentPath.Trim($pathSeparator) $environmentPath = $environmentPath + $pathSeparator [System.Environment]::SetEnvironmentVariable('PATH', $environmentPath, [System.EnvironmentVariableTarget]::$target) Write-Verbose "Add PATH - [$target] - Done" } } Write-Verbose "[$scriptName] - [public] - [Add-EnvironmentPath] - Done" #endregion - From [public] - [Add-EnvironmentPath] #region - From [public] - [Get-EnvironmentPath] Write-Verbose "[$scriptName] - [public] - [Get-EnvironmentPath] - Importing" function Get-EnvironmentPath { <# .SYNOPSIS Get the PATH environment variable. .DESCRIPTION Get the PATH environment variable for the current user or all users. .EXAMPLE Get-EnvironmentPath -Scope CurrentUser Get the PATH environment variable for the current user. .EXAMPLE Get-EnvironmentPath -Scope AllUsers -AsArray Get the PATH environment variable for the current user as an array. #> [OutputType([string[]], ParameterSetName = 'AsArray')] [OutputType([string], ParameterSetName = 'AsString')] [CmdletBinding(DefaultParameterSetName = 'AsString')] param( # The scope of the environment variable. [Parameter()] [ValidateSet('AllUsers', 'CurrentUser')] [string] $Scope = 'CurrentUser', # Return the environment variable as an array. [Parameter(ParameterSetName = 'AsArray')] [switch] $AsArray ) $target = if ($Scope -eq 'CurrentUser') { [System.EnvironmentVariableTarget]::User } else { [System.EnvironmentVariableTarget]::Machine } $environmentPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::$target) if (-not $AsArray) { return $environmentPath } $pathSeparator = [System.IO.Path]::PathSeparator $environmentPath = $environmentPath.Trim($pathSeparator) $environmentPath = $environmentPath.Split($pathSeparator) $environmentPath = $environmentPath | Sort-Object return $environmentPath } Write-Verbose "[$scriptName] - [public] - [Get-EnvironmentPath] - Done" #endregion - From [public] - [Get-EnvironmentPath] #region - From [public] - [Remove-EnvironmentPath] Write-Verbose "[$scriptName] - [public] - [Remove-EnvironmentPath] - Importing" #Requires -Modules Admin, DynamicParams function Remove-EnvironmentPath { <# .SYNOPSIS Remove a path from the PATH environment variable. .DESCRIPTION Remove a path from the PATH environment variable. This command will normalize the path separators. .EXAMPLE Remove-EnvironmentPath -Scope CurrentUser -Path 'C:\Program Files\Git\cmd' Remove the path 'C:\Program Files\Git\cmd' from the PATH environment variable for the current user. .EXAMPLE Remove-EnvironmentPath -Scope AllUsers -Path 'C:\Program Files\Git\cmd' Remove the path 'C:\Program Files\Git\cmd' from the PATH environment variable for all users. .EXAMPLE Remove-EnvironmentPath -Scope CurrentUser -Path 'C:\Program Files\Git\cmd', 'C:\Program Files\Git\bin' Remove the paths 'C:\Program Files\Git\cmd' and 'C:\Program Files\Git\bin' from the PATH environment variable for the current user. .EXAMPLE 'C:\Program Files\Git\cmd', 'C:\Program Files\Git\bin' | Remove-EnvironmentPath -Scope CurrentUser Remove the paths 'C:\Program Files\Git\cmd' and 'C:\Program Files\Git\bin' from the PATH environment variable for the current user. .EXAMPLE (Get-EnvironmentPath -Scope AllUsers -AsArray) | where {$_ -like "$env:USERPROFILE*"} | Remove-EnvironmentPath -Scope AllUsers Remove all paths from the PATH environment variable for all users that start with the current user's profile path. .EXAMPLE (Get-EnvironmentPath -Scope CurrentUser -AsArray) | where {$_ -like "$env:windir*" -or $_ -like "$env:ProgramFiles*" -or $_ -like "${env:ProgramFiles(x86)}*"} | Remove-EnvironmentPath -Scope CurrentUser Remove all paths from the PATH environment variable for the current user that start with the Windows directory, Program Files directory or Program Files (x86) directory. #> [CmdletBinding(SupportsShouldProcess)] param( # The scope of the environment variable. [Parameter()] [ValidateSet('AllUsers', 'CurrentUser')] [string] $Scope = 'CurrentUser' ) dynamicparam { $DynamicParamDictionary = New-DynamicParamDictionary $dynPath = @{ Name = 'Path' Alias = 'FullName' Type = [string[]] Mandatory = $true HelpMessage = 'Name of the font to uninstall.' ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true ValidateSet = if ([string]::IsNullOrEmpty($Scope)) { Get-EnvironmentPath -Scope 'CurrentUser' -AsArray } else { Get-EnvironmentPath -Scope $Scope -AsArray } DynamicParamDictionary = $DynamicParamDictionary } New-DynamicParam @dynPath return $DynamicParamDictionary } begin { $target = if ($Scope -eq 'CurrentUser') { [System.EnvironmentVariableTarget]::User } else { [System.EnvironmentVariableTarget]::Machine if (-not (IsAdmin)) { $errorMessage = @' Administrator rights are required to modify machine PATH. Please run the command again with elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command. '@ throw $errorMessage } } $environmentPath = Get-EnvironmentPath -Scope $Scope -AsArray Write-Verbose "Remove PATH - [$target]" } process { $Path = $PSBoundParameters['Path'] foreach ($envPath in $Path) { Write-Verbose "Remove PATH - [$target] - [$envPath]" $environmentPath = $environmentPath | Where-Object { $_ -ne $envPath } Write-Warning "Remove PATH - [$target] - [$envPath] - Removed" } } end { $pathSeparator = [System.IO.Path]::PathSeparator $environmentPath = $environmentPath -join $pathSeparator $environmentPath = $environmentPath.Trim($pathSeparator) $environmentPath = $environmentPath + $pathSeparator if ($PSCmdlet.ShouldProcess($environmentPath, 'Remove')) { [System.Environment]::SetEnvironmentVariable('PATH', $environmentPath, [System.EnvironmentVariableTarget]::$target) } Write-Verbose "Remove PATH - [$target] - Done" } } Write-Verbose "[$scriptName] - [public] - [Remove-EnvironmentPath] - Done" #endregion - From [public] - [Remove-EnvironmentPath] #region - From [public] - [Repair-EnvironmentPath] Write-Verbose "[$scriptName] - [public] - [Repair-EnvironmentPath] - Importing" #Requires -Modules Admin function Repair-EnvironmentPath { <# .SYNOPSIS Repair the PATH environment variable. .DESCRIPTION Repair the PATH environment variable. This command will remove any invalid paths and normalize the path separators. .EXAMPLE Repair-EnvironmentPath -Scope CurrentUser Repair the PATH environment variable for the current user. .EXAMPLE Repair-EnvironmentPath -Scope AllUsers Repair the PATH environment variable for all users. .EXAMPLE Repair-EnvironmentPath -Scope CurrentUser -Force Repair the PATH environment variable for the current user. Any invalid paths will be removed. .EXAMPLE Repair-EnvironmentPath -Scope AllUsers -Force Repair the PATH environment variable for all users. Any invalid paths will be removed. .NOTES General notes #> [CmdletBinding()] param( # The scope of the environment variable. [Parameter()] [ValidateSet('AllUsers', 'CurrentUser')] [string] $Scope = 'CurrentUser', # Remove any invalid paths. [switch] $Force ) begin { $separatorChar = [System.IO.Path]::DirectorySeparatorChar $target = if ($Scope -eq 'CurrentUser') { [System.EnvironmentVariableTarget]::User } else { [System.EnvironmentVariableTarget]::Machine if (-not (IsAdmin)) { $errorMessage = @' Administrator rights are required to modify machine PATH. Please run the command again with elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command. '@ throw $errorMessage } } $environmentPaths = Get-EnvironmentPath -Scope $Scope -AsArray Write-Verbose "Repair PATH - [$target]" $repairedEnvironmentPaths = @() } process { foreach ($envPath in $environmentPaths) { Write-Verbose "Repair PATH - [$target] - [$envPath]" $environmentPathExists = Test-Path $envPath if ($environmentPathExists) { Write-Verbose "Repair PATH - [$target] - [$envPath] - Path exists - Yes" $envPathObject = Get-Item -Path $envPath -ErrorAction SilentlyContinue if ($envPath -ceq $envPathObject.FullName) { Write-Verbose "Repair PATH - [$target] - [$envPath] - Verify path - Ok" } else { $envPath = $envPathObject.FullName Write-Verbose "Repair PATH - [$target] - [$envPath] - Verify path - Updated" } } else { if ($Force) { Write-Warning "Repair PATH - [$target] - [$envPath] - Path exists - No - Removeing (Force)" continue } else { Write-Warning "Repair PATH - [$target] - [$envPath] - Path exists - No - Continuing (Use -Force to remove))" } } Write-Verbose "Repair PATH - [$target] - [$envPath] - Normalize path" $envPath = $envPath.Replace('\', $separatorChar) $envPath = $envPath.Replace('/', $separatorChar) $envPath = $envPath.TrimEnd($separatorChar) $repairedEnvironmentPaths += $envPath Write-Verbose "Repair PATH - [$target] - [$envPath] - Repaired" } } end { $pathSeparator = [System.IO.Path]::PathSeparator $repairedEnvironmentPaths = $repairedEnvironmentPaths | Sort-Object -Unique $repairedEnvironmentPaths = $repairedEnvironmentPaths -join $pathSeparator $repairedEnvironmentPaths = $repairedEnvironmentPaths.Trim($pathSeparator) $repairedEnvironmentPaths = $repairedEnvironmentPaths + $pathSeparator [System.Environment]::SetEnvironmentVariable('PATH', $repairedEnvironmentPaths, [System.EnvironmentVariableTarget]::$target) Write-Verbose "Repair PATH - [$target] - Done" } } Write-Verbose "[$scriptName] - [public] - [Repair-EnvironmentPath] - Done" #endregion - From [public] - [Repair-EnvironmentPath] Write-Verbose "[$scriptName] - [public] - Done" #endregion - From [public] $exports = @{ Alias = '*' Cmdlet = '' Function = @( 'Add-EnvironmentPath' 'Get-EnvironmentPath' 'Remove-EnvironmentPath' 'Repair-EnvironmentPath' ) Variable = '' } Export-ModuleMember @exports |