Private/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 = @([Environment]::GetEnvironmentVariable($this.Indicator,'Process') -Split $this.Separator) $this.UserLevelEnvPath = @([Environment]::GetEnvironmentVariable($this.Indicator,'User') -Split $this.Separator) $this.MachineLevelEnvPath = @([Environment]::GetEnvironmentVariable($this.Indicator,'Machine') -Split $this.Separator) $this.ProcessLevelEnvPath = $this.DeEmpty($this.ProcessLevelEnvPath) $this.UserLevelEnvPath = $this.DeEmpty($this.UserLevelEnvPath) $this.MachineLevelEnvPath = $this.DeEmpty($this.MachineLevelEnvPath) 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[]] DeEmpty([string[]] $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[]] Append([string[]] $Paths, [string] $Level,[string] $Path){ $buf = $Paths.Clone() if (-not $buf.Contains($Path)){ $buf += $Path }else{ Write-Log "[`$Env:PATH` Duplicated] The $Path in '$Level' level is existing already." -ShowVerbose } return $buf } [void] AppendProcessLevelEnvPath([string] $Path){ $this.DeDuplicateProcessLevelEnvPath() $this.ProcessLevelEnvPath = $this.Append($this.ProcessLevelEnvPath,'Process',$Path) $this.SetEnvPath($this.ProcessLevelEnvPath,'Process') Write-Log "[`$Env:PATH` Modifed] The $Path has been appended into 'Process' level `$Env:PATH`." -ShowVerbose } [void] AppendUserLevelEnvPath([string] $Path){ $this.DeDuplicateUserLevelEnvPath() $this.UserLevelEnvPath = $this.Append($this.UserLevelEnvPath,'User',$Path) $this.SetEnvPath($this.UserLevelEnvPath,'User') Write-Log "[`$Env:PATH` Modifed] The $Path has been appended into 'User' level `$Env:PATH`." -ShowVerbose } [void] AppendMachineLevelEnvPath([string] $Path){ $this.DeDuplicateMachineLevelEnvPath() $this.MachineLevelEnvPath = $this.Append($this.MachineLevelEnvPath,'Machine',$Path) $this.SetEnvPath($this.MachineLevelEnvPath,'Machine') Write-Log "[`$Env:PATH` Modifed] The $Path has been appended into '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() } |