Tag Archives: psobject

Removing a Global Variable – Revisited

14 Nov

I had previously written about an issue that I had with closing out a custom PSObject that caused scripts to fail on subsequent runs. After watching a PluralSight video that covered the concept of passing variables by reference and by value, I re-visited my issue. Initially, I was trying to solve the issue by capturing the variable name and using that name to call:

Remove-Variable -Name 'VariableName'

Although Remove-Variable requires a name to remove the variable, I was going about identifying the name of variable the wrong way. Since the $this variable in the custom PSObject is going to reference the same object as the variable I assigned it to in my scripts I could leverage System.Object.ReferenceEquals() method to identify the variables. My new Close() method for my PSLogging module looks like this:

$tmpVars = Get-Variable -Scope Global | Where-Object{
    [System.Object]::ReferenceEquals($this, $_.Value)}
if($tmpVars.GetType().FullName -eq 'System.Management.Automation.PSVariable'){
    Remove-Variable -Scope Global -Name $tmpVars.Name
}else{
    for($i=0;$i -lt $tmpVars.Count;$i++){
        Remove-Variable -Scope Global -Name $tmpVars[$i].Name
    }
}

I can now reliably identify all references to the log variable and remove them successfully. The concepts of By Value and By Reference weren’t new to me, but I didn’t fully grasp them until watching that video.

Advertisement

Removing a Global Variable from the PowerShell environment

26 Jan

UPDATE: It appears that this fix only works when called from the commandline. InvocationPoint.MyCommand.Definition is populated with the script that called it initially. Back to the drawing board for another solution.

Update 11/9/13: Added source code highlighting; typo fixes

Situation:

I had created a custom PowerShell module to use to log activity in other scripts I was writing. The module exposes a function that outputs a custom PSObject to hold the messages. In my scripts, I assigned this PSObject to a global function so it was available to other scripts I might call. At the end of the script, I wanted a method to close or remove the variable the the PSObject was assigned to so that it wouldn’t cause issues on the subsequent runs.

Issue:

The problem I ran into is there isn’t an easy way for removing the variable holding the PSObject. Trying to set $this = $null in the module doesn’t null out the containing object but the $this variable instead. Attempting to remove the variable with the Remove-Variable and $this also failed. My temporary solution was to iterate through all of the NoteProperty’s that were set and $null them out individually. This worked for a while, but required me to close and reopen the ISE between running scripts as the next attempt to run a script caused PowerShell to complain that it couldn’t add to the log variable.

Solution:

I finally tired of having to reopen the ISE and decided to fix my problem properly. The following is my solution:

function Get-VariableName{ 
    param() 
    $tmpRegex = '(?<=$[A-Z,a-z,0-9]*:).*(?=(s=|=))' 
    $this.InvocationPoint.MyCommand.Definition -match $tmpRegex | Out-Null 
    return $Matches[0].Trim() 
}

…

# Close # 
$tmpObject | Add-Member -MemberType ScriptMethod -Name Close ` 
    -Value { 
        param() 
        Remove-Item -Path "Variable:$(Get-VariableName)" 
}

The Get-VariableName uses regex to parse the variable name from the InvocationPoint of $this. The property $this.InvocationPoint.MyCommand.Definition exposes the full command used to create the variable. This was the only place I could find this information exposed in the object itself without adding a property. Now that I had the variable name, I used the Remove-Item function to remove the variable. That is probably the long way of removing instead of just using:

Remove-Variable –Name $(Get-VariableName) –Scope Global

Somehow I overlooked that command when I implemented the fix.

This works for now, but I may need to update the regex at some point to support both global and none global variables as I believe it will fail to capture none global variables. Fortunately I only use this with globally defined variables.