Home windows automation inevitably includes updating path surroundings variables. The commonest is the Home windows path (Variable: PATH), however more and more we’re all having to concentrate to the PowerShell module path (Variable: PSModulePath).
Over time I’ve realized a lot of the errors you can also make when manipulating these paths first hand (Yep, there’s a particular flat spot on my brow only for the place I’ve banged it on the desk attributable to path points).
The primary 4 essential gadgets that journey most individuals up are:
- That the Course of degree PATH variable is a mixture of each the Machine and Consumer paths.
- That any surroundings variables saved within the registry strings for Machine and Consumer are totally expanded within the Course of degree PATH variable.
- Forgetting that many different installations replace the trail – which suggests you actually can’t have a “international” view of what’s in all paths in your total firm, which makes the subsequent level much more problematic…
- Manipulating the trail as a string with search and exchange or common expressions – particularly on condition that there typically no solution to know the sum whole of all paths that is perhaps contained on all of the machines that you’ll goal along with your automation – there’s a higher manner 😉
Let’s leap proper into a listing of path manipulation errors so that you simply may discover the one which introduced you right here, and so that you simply acquire an appreciation for the problem of coding to addresses a number of the ones you haven’t even tripped over but 😉
Path Manipulation Errors
- Assuming good clear paths – that not one of the following record of errors are NOT ALREADY MADE by one thing earlier than your automation (both automation scripting or software program installers).
- Blinding including a path with out checking if the trail you want to add already exists on the trail you want to add it to (thereby duplicating it)
- forgetting to examine if the trail you want to add is already there with and with out a trailing slash as a result of each are legitimate and it’s stunning what number of occasions this element causes duplicated paths.
- Utilizing case-sensitive checks when checking if the trail already exists.
- Not dealing with surroundings variables embedded in paths accurately. In the event you examine the method surroundings variable (
%PATH%
), surroundings variable expansions are already finished. If in case you have Java put in your “PATH” in all probability accommodates"%JAVA_HOMEpercentbin"
, nonetheless, if you happen to study$env:path
, you will note that%JAVA_HOME%
is expanded. So if you happen to’re not cautious you’ll learn$env:path
after which overwrite the registry path after including your path. You find yourself altering %JAVA_HOME% to a literal reference – which you received’t catch till the subsequent Java replace when %JAVA_HOME% modifications. So that you need to guarantee that you’re and changing values with UNEXPANDED surroundings variables. - Studying the expanded, mixed PATH variable – including to it – and overwriting the system path. The PATH variable in a course of is [a] a mixture of each consumer and machine paths and [b] has all surroundings variables expanded. Once you learn this congolmerate path and write it again to the system path, you propagate consumer paths into the system broad path. A few of these consumer paths could level to areas which are solely related to the consumer profile the place the trail replace was made.
- Not with the ability to take away paths with embedded surroundings variables attributable to checking for and trying to take away the EXPANDED worth.
- Checking the method PATH variable for existence of a path and never updating the machine path as a result of there was an identical worth within the consumer path – nonetheless, after not updating the machine path – the trail won’t be obtainable to different customers.
- Updating the Machine path, however not additionally updating the present PROCESS in order that the trail is out there instantly – generally automators take reboots to resolve this – however the included code can be utilized to replace the present course of in order that the brand new location resolves on the system path instantly.
- When doing removals, you don’t take away all duplicate situations of a path – which generally are there attributable to dangerous installers or your individual earlier practices – removals ought to take away all equivalent copies of the identical path.
- parsing issues with too many or too few semi-colon delimiters (’;’)
- Not utilizing the identical self-discipline and logic with path variables aside from PATH with all the identical performance (e.g. PsModulePath).
- not appropriately dealing with the truth that present paths and a few that you’re working with comprise areas (or killing many hours coding to deal with it correctly).
- including an unexpanded surroundings variable to the Course of path – this doesn’t work as a result of home windows path variable processing assumes that each one surroundings expansions had been finished at course of setup time.
- Generally components of a path are within the PATH twice as a result of a path and a subpath of that path are each on path (e.g. “C:Program FilesABC” and “C:Program FilesABCTemplates”). In the event you manipulate it with string or regex capabilities and don’t take away the longer path first, you’re prone to soiling the trail with an entry for the precise string “Templates”.
- Utilizing regex or customary search / exchange logic to govern path – I might write a e book on this one – it is vitally arduous to craft a regex or search exchange that does what you count on, however nothing extra. Add to that each one sorts of character escaping and the potential of partial matches and dealing with areas it will get tough quick.
- The entire above mistaken practices can result in an extended and longer path with invalid or duplicate entries – this implies any calls wherever within the system that depend on the trail begin to take longer and longer.
Design Components Of the Included Code To Scale back Path Manipulation Errors
- Utilizing the [Environment] kind offers with all path information with the surroundings variables UNEXPANDED.
- Utilizing the [Environment] kind forces the selecting of a path scope or context => Machine, Consumer or Course of – it’s important to choose one.
- Breaking the trail into an array: [a] avoids common expressions, search and exchange and a myriad of different parsing points (keep in mind many different issues could have up to date the trail and so that you really can’t know all of the gadgets that may match your search expression), [b] straightforward removing of duplicate paths, [c] eliminates semi-colon delimiter frustrations.
- Idempotent code makes positive it solely provides the trail if it doesn’t exist already. For this reason the operate identify begins with “Guarantee”.
- case insensitivity ensures issues work when your path case doesn’t match precisely.
- helps including to the beginning or finish of the trail – defaults to the tip as that’s most typical.
- cleans up the ever so widespread empty path entries from earlier dangerous removals (double semi-colons).
- Errors upon an try so as to add an unexpanded surroundings variable to a Course of degree path. The surroundings variable won’t be expanded by home windows when looking out the Course of path because it assumes all surroundings variable growth was finished at course of setup time. This solely applies to Course of degree paths that are by no means persistently saved when the method ends.
- These capabilities are designed for compactness in an effort to insert them inline into present single goal scripts – so within the identify of compactness, they don’t observe PowerShell greatest practices for parameters, embedded assist or coding fashion. I’m discovering I particularly favor this method when constructing PowerShell chucks that run as half of a bigger orchestration system like Packer or CloudFormation.
Some Different Good-To-Is aware of
- In the event you want the trail instantly added or eliminated out of your present course of – then additionally execute the operate utilizing the “Course of” scope.
- Service Supervisor solely reads it’s path on system bootup, you may replace it with one thing you want to use in subsequent automation and even replace the present course of path – however discover that the trail nonetheless isn’t obtainable. This occurs in instances of orchestration applied sciences that use a service to run bits of code in a brand new course of every time they run a section. The present course of just isn’t related to new segments of code and the service internet hosting the automation received’t be up to date till you reboot the system and repair supervisor will get the brand new path. That is precisely the issue with packer automation the place you put in some automation software program with a system path replace in a single “provisioner” and attempt to use it in one other. There two options:[1] one is to reboot and the opposite is [2] to maintain including that path to any subsequent automation that wants it till a reboot is carried out. Choice 1 is one of the best if you happen to can’t predict what may want the trail earlier than the subsequent reboot or you could have advanced or “dynamically composed” automation stacks.
This Code In Manufacturing
Though it appears fairly a bit completely different, I used this code to replace a Chocolatey helper to work accurately: https://github.com/chocolatey/choco/blob/grasp/src/chocolatey.assets/helpers/capabilities/Set up-ChocolateyPath.ps1 and to create a brand new Chocolatey helper for uninstall: https://github.com/chocolatey/choco/blob/grasp/src/chocolatey.assets/helpers/capabilities/Uninstall-ChocolateyPath.ps1. In each instances this code just isn’t within the hyperlinks indicated till the pull requests are merged for the Chocolatey 0.10.4 launch.
Up to date Code
The beneath code’s major house is on the next repository (the place it is perhaps improved upon in comparison with the beneath): https://gitlab.com/missionimpossiblecode/MissionImpossibleCode
Guarantee-OnPath Operate
Operate Guarantee-OnPath ($PathToAdd,$Scope,$PathVariable,$AddToStartOrEnd)
{
If (!$Scope) {$Scope='Machine'}
If (!$PathVariable) {$PathVariable='PATH'}
If (!$AddToStartOrEnd) {$AddToStartOrEnd='END'}
If (($PathToAdd -ilike '*%*') -AND ($Scope -ieq 'Course of')) {Throw 'Unexpanded surroundings variables don't work on the Course of degree path'}
write-host "Making certain `"$pathtoadd`" is added to the $AddToStartOrEnd of variable `"$PathVariable`" for scope `"$scope`" "
$ExistingPathArray = @([Environment]::GetEnvironmentVariable("$PathVariable","$Scope").cut up(';'))
if (($ExistingPathArray -inotcontains $PathToAdd) -AND ($ExistingPathArray -inotcontains "$PathToAdd"))
{
If ($AddToStartOrEnd -ieq 'START')
{ $Newpath = @("$PathToAdd") + $ExistingPathArray }
else
{ $Newpath = $ExistingPathArray + @("$PathToAdd") }
$AssembledNewPath = ($newpath -join(';')).trimend(';')
[Environment]::SetEnvironmentVariable("$PathVariable",$AssembledNewPath,"$Scope")
}
}
#Check code
Guarantee-OnPath '%TESTpercentbin'
$env:ABC = 'C:ABC'
Guarantee-OnPath '%ABC%' 'Machine' 'PSModulePath' 'START'
Guarantee-OnPath 'C:ABC' 'Course of' 'PSModulePath' 'START' #Make obtainable in present course of, cannot use surroundings variables
#Present Modification Outcomes
[Environment]::GetEnvironmentVariable("PATH","Course of")
[Environment]::GetEnvironmentVariable("PSModulePath","Machine")
[Environment]::GetEnvironmentVariable("PSModulePath","Course of")
Guarantee-RemovedFromPath Operate
Operate Guarantee-RemovedFromPath ($PathToRemove,$Scope,$PathVariable)
{
If (!$Scope) {$Scope='Machine'}
If (!$PathVariable) {$PathVariable='PATH'}
$ExistingPathArray = @([Environment]::GetEnvironmentVariable("$PathVariable","$Scope").cut up(';'))
write-host "Making certain `"$PathToRemove`" is faraway from variable `"$PathVariable`" for scope `"$scope`" "
if (($ExistingPathArray -icontains $PathToRemove) -OR ($ExistingPathArray -icontains "$PathToRemove"))
{
foreach ($path in $ExistingPathArray)
{
If ($Path)
{
If (($path -ine "$PathToRemove") -AND ($path -ine "$PathToRemove"))
{
[string[]]$Newpath += "$path"
}
}
}
$AssembledNewPath = ($Newpath -join(';')).trimend(';')
[Environment]::SetEnvironmentVariable("$PathVariable",$AssembledNewPath,"$Scope")
}
}
Guarantee-RemovedFromPath '%TESTpercentbin'
Guarantee-RemovedFromPath '%ABC%' 'Machine' 'PSModulePath'
Guarantee-RemovedFromPath 'C:ABC' 'Machine' 'PSModulePath'
[Environment]::GetEnvironmentVariable("PATH","Machine")
[Environment]::GetEnvironmentVariable("PSModulePath","Machine")
[Environment]::GetEnvironmentVariable("PSModulePath","Course of")