Many times while authoring PowerShell scripts, the expected output will be incorrect because PowerShell ISE does not automatically cleanup it’s variable between manual runs of a script. In my experience this poses two practical issue which lead to incorrect script results:
1) If the variable is not explicitly re-initialized in the script (very common practice), the script will be initialized with a value from the previous run, and,
2) If a script is changed so that a variable is not properly assigned a value, PowerShell ISE will still show the value from the previous run because it has not been assigned a new value since
This all leads to confusion. I’ve been trying to find the best way to clear all the variables a script has set a value for without restarting PowerShell ISE.
I am not particular happy with what I’ve come up with, but suffice to say, so far, this seems to be the easiest and quickest method:
Remove-Variable * -ErrorAction SilentlyContinue; Remove-Module *; $error.Clear(); Clear-Host
Here is a shorter version using aliases:
rv * -ea SilentlyContinue; rmo *; $error.Clear(); cls
** Note: this will indiscriminately remove ANY variables set during your PowerShell ISE session – not just the ones specific to the script you are working on.
Microsoft MVP Pat Richards has a similar approach which analyses the actual .ps script file to identify and remove only the variables used in the script. He wraps this in a function which can be invoked at anytime: https://www.ucunleashed.com/247.
function Remove-ScriptVariables($path) {
$result = Get-Content $path |
ForEach {if ( $_ -match ‘(\$.*?)\s*=’) {
$matches[1] | ? { $_ -notlike ‘*.*’ -and $_ -notmatch ‘result’ -and $_ -notmatch ‘env:’}
}}
ForEach ($v in ($result | Sort-Object | Get-Unique)) {
Write-Host “Removing” $v.replace(“$”,””)
Remove-Variable ($v.replace(“$”,””)) -ErrorAction SilentlyContinue
}}
# end function Get-ScriptVariables
For reasons I cannot figure out, Remove-Variable does not always remove all the variables for me using this function; but I like the approach.
So here is another method that works well:
- At the start of your script, include this line which gets the state of the variables before the script is run:
- $DefaultVariables = $(Get-Variable).Name
- Then at the end of your script, do a comparison and remove all of the variables added:
- ((Compare-Object -ReferenceObject (Get-Variable).Name -DifferenceObject $DefaultVariables).InputObject).foreach{Remove-Variable -Name $_}
This seems to work consistently the best.
Thanks for this! I’ve recently started using ISE in favor of VS Code for debugging and noticed my script results were wonky due to the lingering variables.
Your last point about the pre and follow up variables check, the cleaning just the difference – is exactly what I was after. I was trying to identify other means to determine whether a variable was created by the script or not (scope is one thought but not when variables have other scopes explicitly set).
Now I just need to figure out the answer to my question about whether or not variables defined in the process block will need to be cleared or if they are automatically cleared after each object is processed…
last part, step 2:
((Compare-Object -ReferenceObject (Get-Variable).Name -DifferenceObject $DefaultVariables).InputObject).foreach{Remove-Variable -Name $_}
I think the .foreach is supposed to be |foreach
((Compare-Object -ReferenceObject (Get-Variable).Name -DifferenceObject $DefaultVariables).InputObject)|foreach{Remove-Variable -Name $_}