Skip to content

Instantly share code, notes, and snippets.

@mklement0
Created October 10, 2018 02:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mklement0/a71eee0f61213935937173b52defd778 to your computer and use it in GitHub Desktop.
Save mklement0/a71eee0f61213935937173b52defd778 to your computer and use it in GitHub Desktop.
PowerShell script/function that invokes a command with a temporarily modified environment.
function Invoke-WithEnvironment {
<#
.SYNOPSIS
Invokes commands with a temporarily modified environment.
.DESCRIPTION
Modifies environment variables temporarily based on a hashtable of values,
invokes the specified script block, then restores the previous environment.
.PARAMETER Environment
A hashtable that defines the temporary environment-variable values.
Assign $null to (temporarily) remove an environment variable that is
currently set.
.PARAMETER ScriptBlock
The command(s) to execute with the temporarily modified environment.
.EXAMPLE
Invoke-WithEnvironment @{ PORT=8080 } { node index.js }
Runs node with environment variable PORT temporarily set to 8080, with its
previous value, if any, restored afterwards.
#>
param(
[Parameter(Mandatory)] [System.Collections.IDictionary] $Environment,
[Parameter(Mandatory)] [scriptblock] $ScriptBlock
)
# Modify the environment based on the hashtable and save the original
# one for later restoration.
$htOrgEnv = @{}
foreach ($kv in $Environment.GetEnumerator()) {
$htOrgEnv[$kv.Key] = (Get-Item -EA SilentlyContinue "env:$($kv.Key)").Value
Set-Item "env:$($kv.Key)" $kv.Value
}
# Invoke the script block
try {
& $ScriptBlock
} finally {
# Restore the original environment.
foreach ($kv in $Environment.GetEnumerator()) {
# Note: setting an environment var. to $null or '' *removes* it.
Set-Item "env:$($kv.Key)" $htOrgEnv[$kv.Key]
}
}
}
# -- Generic code that handles the invocation.
if ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq '') { # Being dot-sourced
if ($MyInvocation.Line -eq '' -and $host.Name -eq 'Visual Studio Code Host') { # Support for debugging in VSCode
# If the current file is directly launched for debugging from the editor,
# use a custom invocation with arguments for debugging.
Write-Warning 'VSCode debugging: Invoking embedded function with custom arguments.'
& ([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)) # Add arguments for debugging here.
} else {
# Nothing further to do: the function has been defined in the current scope for *later* use.
# However, we warn if arguments were unexpectedly passed or something is being piped.
if ($Args.Count -or $MyInvocation.ExpectingInput) { Write-Warning "Ignoring arguments and/or pipeline input due to being dot-sourced: $PSCommandPath" }
}
} else { # Script is invoked directly (by name/path directly or via &)
# Call the embedded function of the same name, relaying any arguments passed.
if ($MyInvocation.ExpectingInput) { # pipeline input present
$Input | & ([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)) @Args
} else { # only arguments, if any
& ([System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)) @Args
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment