Last active
May 26, 2019 09:30
-
-
Save alshain/0376c093b3436127b118604518a88058 to your computer and use it in GitHub Desktop.
Resolve-Variable.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Todo create cmdlet | |
# TODOs | |
# Does not properly recognize variable expansions, because GetEnvironmentVariables already does that... probably with the current process' environment variables | |
# | |
function GetCurrentUserPathVariableRaw() { | |
if ($env:USERDOMAIN.Length -eq 0) { | |
throw "Does not yet support no domains" | |
} | |
$userFilter = "$env:USERDOMAIN\\$env:USERNAME" | |
Write-Output (Get-WmiObject -Query "select * from Win32_Environment WHERE Name = 'PATH' and UserName = '$userFilter'").VariableValue | |
} | |
function GetSystemPathVariableRaw() { | |
Write-Output (Get-WmiObject -Query "select * from Win32_Environment WHERE Name = 'PATH' and SystemVariable = true").VariableValue | |
} | |
function NormalizedPath($path) { | |
return (Join-Path $path "") | |
} | |
function NormalizedPathToLower() { | |
param ( | |
# Path | |
[Parameter()] | |
[string] | |
$Path | |
) | |
return (Join-Path $Path "").ToLowerInvariant() | |
} | |
function ContainsEnvironmentVars() { | |
param ( | |
# Path | |
[Parameter()] | |
[string] | |
$pathEntry | |
) | |
return $pathEntry -match "%\S+\%" | |
} | |
# Adapted from: | |
# https://powershell.org/2012/06/friday-fun-expand-environmental-variables-in-powershell-strings/ | |
# | |
# Fixes: "%SYSTEMROOT%\" (Get-Item would expand `\` to *all* ENV variables) | |
# Fixes: "%SYSTEMROOT%PATH" Would expand both SYSTEMROOT *and* PATH, instead of only %SYSTEMROOT% | |
# Trying to be consistent with what CMD does in its expansion | |
# echo "%SYSTEMROOT%PATH%"" will evaluate to `<SYSTEMROOT>PATH%` | |
# echo "%SYSTEMROOT%%PATH%"" will evaluate to `<SYSTEMROOT><PATH>` | |
# echo "%SYSTEMROOT%%%PATH%"" will evaluate to `<SYSTEMROOT><PATH>` | |
# echo "%DOESNOTEXIST%PATH%"" will evaluate to `DOESNOTEXIST<PATH>` | |
Function Resolve-EnvVariable { | |
[cmdletbinding()] | |
Param( | |
[Parameter(Position=0,ValueFromPipeline=$True,Mandatory=$True, | |
HelpMessage="Enter a string that contains an environmental variable like %WINDIR%")] | |
[ValidateNotNullOrEmpty()] | |
[string]$String | |
) | |
Begin { | |
Write-Verbose "Starting $($myinvocation.mycommand)" | |
} #Begin | |
Process { | |
#if string contains a % then process it | |
if ($string -match "%\S+%") { | |
Write-Verbose "Resolving environmental variables in $String" | |
#split string into an array of values | |
$values=$string.Split("%") | |
# We only enounter a variable after the first `%` | |
$isVariable = $false | |
$totalFragments = $values.Count | |
$fragment = 0; | |
foreach ($text in $values) { | |
$fragment++; | |
if ($totalFragments -eq $fragment) { | |
# If we're looking at the last fragment, it can't be a variable because it would need to be followed by another `%` | |
# Prevents trailing `%PATH` in $String from being parsed as a variable | |
if ($isVariable) { | |
$isVariable = $false; | |
# We need to add the percentage sign manually here for the "unresolved" variable | |
$newstring += "%$text" | |
# We're at the end anyway, but we need to prevent adding `$text` twice. | |
# We can't use the regular non-variable case instead, because then we'd be missing the `%` | |
break | |
} | |
} | |
#find the corresponding value in ENV: | |
if ($isVariable) { | |
Write-Verbose "Looking for $text" | |
# Prevent accessing "\" element by accident, assuming there are always more than one ENV variable | |
$variable = (Get-Item env:$text -erroraction "SilentlyContinue") | |
# In case we end up | |
$success = $false | |
$resultCount = ($variable | Measure-Object).Count | |
if ($text -eq "\" -or $text -eq ".") { | |
# Special case this information | |
Write-Verbose "Tried to access $text, this would access ALL env variables, skipping..." | |
} | |
elseif ($resultCount -gt 1) { | |
Write-Verbose "Found too many results, potentially accessed `\`: $variable" | |
} | |
elseif ($resultCount -eq 0) { | |
Write-Verbose "Did not find $text" | |
} | |
# Separate IF such that we can consolidate error handling | |
if ($resultCount -eq 1) { | |
$replace = $variable.Value | |
#if found append it to the new string | |
Write-Verbose "Found $replace" | |
$newstring+=$replace | |
# Only here we actually found our variable, in the other cases, the next % sign can again start a variable | |
$isVariable = $false | |
} else { | |
#otherwise append the original text | |
# Problem: If there is an unbalanced amount of `%` in the string, this will balance it incorrectly | |
# We can't put both `%` here, because we don't know whether this string actually | |
$newstring += "%$text" | |
# Don't reset isVariable to false, because `cmd > echo %DOESNOTEXIST%PATH%` would try to match on `%PATH` next | |
} | |
} else { | |
# Don't log empty parts | |
if ($text) { | |
Write-Verbose "Appending non-variable part for $text" | |
$newstring += $text | |
} | |
$isVariable = $true | |
} | |
} #foreach value | |
Write-Verbose "Writing revised string to the pipeline" | |
#write the string back to the pipeline | |
Write-Output $NewString | |
} #if | |
else { | |
#skip the string and write it back to the pipeline | |
Write-Output $String | |
} | |
} #Process | |
End { | |
Write-Verbose "Ending $($myinvocation.mycommand)" | |
} #End | |
} #end Resolve-EnvVariable | |
function Test-Resolve-EnvVariable() { | |
param( | |
# Test-String | |
[Parameter(Mandatory=$true)] | |
[string] | |
$String, | |
# Expected Value | |
[Parameter(Mandatory=$true)] | |
[string] | |
$Expected | |
) | |
if ((Resolve-EnvVariable $String) -ne $Expected) { | |
$result = Resolve-EnvVariable $String -Verbose | |
Write-Host "Resolve-EnvVariable for: $String" | |
Write-Host "> should expand to: $Expected" | |
Write-Host "> instead, it resolved to: $result" | |
Write-Host $result | |
Write-Host | |
Write-Host "See above for VERBOSE trace" | |
} | |
else { | |
Write-Host "Resolve-EnvVariable $($String): OK" | |
} | |
} | |
Test-Resolve-EnvVariable "%SYSTEMROOT%\" "EXPECT-MISMATCH" # Sanity test | |
Test-Resolve-EnvVariable "%SYSTEMROOT%\" "$env:SYSTEMROOT\" | |
Test-Resolve-EnvVariable "%SYSTEMROOT%PATH%" "$($env:SYSTEMROOT)PATH%" | |
Test-Resolve-EnvVariable "%SYSTEMROOT%%PATH%" "$($env:SYSTEMROOT)$($env:PATH)" | |
Test-Resolve-EnvVariable "%SYSTEMROOT%%%PATH" "$env:SYSTEMROOT%%PATH" | |
Test-Resolve-EnvVariable "%SYSTEMROOT%%%PATH%" "$env:SYSTEMROOT%$env:PATH" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment