Public/Classes/EnvPath.ps1
class EnvPath{ <# .DESCRIPTION A class that maintains the process, user, and machine level `$Env:PATH`, holds the de-duplicated paths, and provides some useful methods for some scenarios that need to modify the `$Env:PATH`. .INPUTS None. .OUTPUTS EnvPath. .NOTES Do not check any path's existence or validity. #> [ValidateNotNullOrEmpty()][string] $OriginalPlatform [ValidateNotNullOrEmpty()][string] $Indicator [ValidateNotNullOrEmpty()][string] $Separator [ValidateNotNullOrEmpty()][string[]] $ProcessLevelEnvPath [AllowNull()][string[]] $UserLevelEnvPath [AllowNull()][string[]] $MachineLevelEnvPath [ValidateNotNullOrEmpty()][string[]] $DeDuplicatedProcessLevelEnvPath [AllowNull()][string[]] $DeDuplicatedUserLevelEnvPath [AllowNull()][string[]] $DeDuplicatedMachineLevelEnvPath EnvPath() { if ([Environment]::OSVersion.Platform -eq "Win32NT"){ $this.OriginalPlatform = "Win32NT" $this.Indicator = 'Path' $this.Separator = ';' }elseif ([Environment]::OSVersion.Platform -eq "Unix") { $this.OriginalPlatform = "Unix" $this.Indicator = 'PATH' $this.Separator = ':' }else{ throw "Only Win32NT and Unix are supported, not $($global:PSVersionTable.Platform)." } $this.ProcessLevelEnvPath = $this.DeEmptyAndDeShadow([Environment]::GetEnvironmentVariable($this.Indicator,'Process') -Split $this.Separator) $this.UserLevelEnvPath = $this.DeEmptyAndDeShadow([Environment]::GetEnvironmentVariable($this.Indicator,'User') -Split $this.Separator) $this.MachineLevelEnvPath = $this.DeEmptyAndDeShadow([Environment]::GetEnvironmentVariable($this.Indicator,'Machine') -Split $this.Separator) if ($this.OriginalPlatform -eq "Unix"){ if ($this.UserLevelEnvPath.Count -ne 0){ throw "In Unix platform, the User level `$Env:PATH` should be empty. But it is $($this.UserLevelEnvPath)." } if ($this.MachineLevelEnvPath.Count -ne 0){ throw "In Unix platform, the Machine level `$Env:PATH` should be empty. But it is $($this.MachineLevelEnvPath)." } } $verbose = $false $this.DeDuplicatedProcessLevelEnvPath = $this.DeDuplicate($this.ProcessLevelEnvPath,'Process',$verbose) $this.DeDuplicatedUserLevelEnvPath = $this.DeDuplicate($this.UserLevelEnvPath,'Process',$verbose) $this.DeDuplicatedMachineLevelEnvPath = $this.DeDuplicate($this.MachineLevelEnvPath,'Process',$verbose) } [void] FindDuplicatedPaths([string[]] $Paths, [string] $Level,[bool]$Verbose){ $grouped_paths = $Paths | Group-Object $duplicated_groups = $grouped_paths | Where-Object { $_.Count -gt 1 } if ($Verbose){ foreach ($group in $duplicated_groups) { Write-Log "[`$Env:PATH` Duplicated] The $($group.Name) in '$Level' level `$Env:PATH` exists $($group.Count) times." -ShowVerbose } }else{ foreach ($group in $duplicated_groups) { Write-Log "[`$Env:PATH` Duplicated] The $($group.Name) in '$Level' level `$Env:PATH` exists $($group.Count) times." } } } [string[]] DeEmptyAndDeShadow([string[]] $Paths){ # remove '' and '.' paths $buf = @() foreach ($item in $Paths) { if ($item.Trim('. ')){ $buf += $item } } return $buf } [string[]] DeDuplicate([string[]] $Paths, [string] $Level,[bool]$Verbose){ $this.FindDuplicatedPaths($Paths,$Level,$Verbose) $buf = @() foreach ($item in $Paths) { if (-not $buf.Contains($item)){ $buf += $item } } return $buf } [void] SetEnvPath([string[]] $Paths, [string] $Level){ [Environment]::SetEnvironmentVariable($this.Indicator,$Paths -join $this.Separator,$Level) } [void] DeDuplicateProcessLevelEnvPath(){ $verbose = $true $this.ProcessLevelEnvPath = $this.DeDuplicate($this.ProcessLevelEnvPath,'Process',$verbose) $this.SetEnvPath($this.ProcessLevelEnvPath,'Process') Write-Log "[`$Env:PATH` Modifed] The 'Process' level `$Env:PATH` has been de-duplicated." -ShowVerbose } [void] DeDuplicateUserLevelEnvPath(){ $verbose = $true $this.UserLevelEnvPath = $this.DeDuplicate($this.UserLevelEnvPath,'User',$verbose) $this.SetEnvPath($this.UserLevelEnvPath,'User') Write-Log "[`$Env:PATH` Modifed] The 'User' level `$Env:PATH` has been de-duplicated." -ShowVerbose } [void] DeDuplicateMachineLevelEnvPath(){ $verbose = $true $this.MachineLevelEnvPath = $this.DeDuplicate($this.MachineLevelEnvPath,'Machine',$verbose) $this.SetEnvPath($this.MachineLevelEnvPath,'Machine') Write-Log "[`$Env:PATH` Modifed] The 'Machine' level `$Env:PATH` has been de-duplicated." -ShowVerbose } [void] MergeDeDuplicatedEnvPathFromMachineLevelToUserLevel(){ $this.DeDuplicateUserLevelEnvPath() $this.DeDuplicateMachineLevelEnvPath() $buf = $this.UserLevelEnvPath+$this.MachineLevelEnvPath $verbose = $true $this.FindDuplicatedPaths($buf,'User+Machine',$verbose) $buf = @() foreach ($item in $this.MachineLevelEnvPath) { if (-not $this.UserLevelEnvPath.Contains($item)){ $buf += $item } } $this.MachineLevelEnvPath = $buf $this.SetEnvPath($this.MachineLevelEnvPath,'Machine') Write-Log "[`$Env:PATH` Modifed] The items duplicated across 'Machine' level and 'User' level `$Env:PATH` have been merged into 'User' level `$Env:PATH`." -ShowVerbose } [string[]] Insert([string[]] $Paths, [string] $Level,[string] $Path,[bool] $IsAppend){ $buf = @() $exist = $false foreach ($item in $Paths) # extract the duplicated path { if ($item -eq $Path){ $exist = $true if ($IsAppend){ Write-Log "[`$Env:PATH` Adjustment] The $Path in '$Level' level already exists and will be tweaked to the end." -ShowVerbose }else{ Write-Log "[`$Env:PATH` Adjustment] The $Path in '$Level' level already exists and will be tweaked to the beginning." -ShowVerbose } }else{ $buf += $item } } if ($IsAppend){ $buf += $Path if (-not $exist){ Write-Log "[`$Env:PATH` To Modify] The $Path will been appended into $Level level `$Env:PATH`." -ShowVerbose } }else{ $buf = @($Path)+$buf if (-not $exist){ Write-Log "[`$Env:PATH` To Modify] The $Path will been prepended into $Level level `$Env:PATH`." -ShowVerbose } } return $buf } [void] AddProcessLevelEnvPath([string] $Path, [bool] $IsAppend){ $this.DeDuplicateProcessLevelEnvPath() $this.ProcessLevelEnvPath = $this.Insert($this.ProcessLevelEnvPath,'Process',$Path,$IsAppend) $this.SetEnvPath($this.ProcessLevelEnvPath,'Process') Write-Log "[`$Env:PATH` Modifed] The addition has been done on 'Process' level `$Env:PATH`." -ShowVerbose } [void] AddUserLevelEnvPath([string] $Path, [bool] $IsAppend){ $this.DeDuplicateUserLevelEnvPath() $this.UserLevelEnvPath = $this.Insert($this.UserLevelEnvPath,'User',$Path,$IsAppend) $this.SetEnvPath($this.UserLevelEnvPath,'User') Write-Log "[`$Env:PATH` Modifed] The addition has been done on 'User' level `$Env:PATH`." -ShowVerbose } [void] AddMachineLevelEnvPath([string] $Path, [bool] $IsAppend){ $this.DeDuplicateMachineLevelEnvPath() $this.MachineLevelEnvPath = $this.Insert($this.MachineLevelEnvPath,'Machine',$Path,$IsAppend) $this.SetEnvPath($this.MachineLevelEnvPath,'Machine') Write-Log "[`$Env:PATH` Modifed] The addition has been done on 'Machine' level `$Env:PATH`." -ShowVerbose } [string[]] Remove([string[]] $Paths, [string] $Level, [string] $Path, [bool] $IsPattern){ $buf = @() foreach ($item in $Paths) { if ($IsPattern){ if ($item -NotMatch $Path){ $buf += $item }else{ Write-Log "[`$Env:PATH` to Remove] The $item in '$Level' level will be removed." -ShowVerbose } }else{ if ($item -ne $Path){ $buf += $item }else{ Write-Log "[`$Env:PATH` to Remove] The $item in '$Level' level will be removed." -ShowVerbose } } } return $buf } [void] RemoveProcessLevelEnvPath([string] $Target, [bool] $IsPattern){ $this.DeDuplicateProcessLevelEnvPath() $this.ProcessLevelEnvPath = $this.Remove($this.ProcessLevelEnvPath,'Process',$Target,$IsPattern) $this.SetEnvPath($this.ProcessLevelEnvPath,'Process') Write-Log "[`$Env:PATH` Modifed] The removement has been done on 'Process' level `$Env:PATH`." -ShowVerbose } [void] RemoveUserLevelEnvPath([string] $Target, [bool] $IsPattern){ $this.DeDuplicateUserLevelEnvPath() $this.UserLevelEnvPath = $this.Remove($this.UserLevelEnvPath,'User',$Target,$IsPattern) $this.SetEnvPath($this.UserLevelEnvPath,'User') Write-Log "[`$Env:PATH` Modifed] The removement has been done on 'User' level `$Env:PATH`." -ShowVerbose } [void] RemoveMachineLevelEnvPath([string] $Target, [bool] $IsPattern){ $this.DeDuplicateMachineLevelEnvPath() $this.MachineLevelEnvPath = $this.Remove($this.MachineLevelEnvPath,'Machine',$Target,$IsPattern) $this.SetEnvPath($this.MachineLevelEnvPath,'Machine') Write-Log "[`$Env:PATH` Modifed] The removement has been done on 'Machine' level `$Env:PATH`." -ShowVerbose } } function Get-EnvPath{ <# .DESCRIPTION A function to apply the class EnvPath. Return an instance of it. .INPUTS None. .OUTPUTS EnvPath. #> param() return [EnvPath]::new() } |