Differentiating Between Built-In and User-Defined Variables

by MattG at 2013-01-26 07:49:11

Does anyone know how to programmatically differentiate between a built-in variable (e.g. $PID, $PSVersionTable) and a user-defined variable? I tried interrogating the various public/private members of the System.Management.Automation.PSVariable class to see if there was a field that made this differentiation. Alas, I found no such field.

If anyone has any creative solutions, I’d love to know!
by KaiY at 2013-01-27 15:31:12
you could create a hashtable from the output of “Get-Variable”. Members of this hashtable are built-in, others not.
by MattG at 2013-01-27 15:52:04
Get-Variable lists both built-in and user-defined variables.

After chatting with several MVPs I’ve come to the conclusion that there is ultimately no simple, automated way to differentiate. I ended up just manually adding all built-in variables to a hashtable. All in all, it wasn’t too painful. It just doesn’t lend itself to maintainability.
by nohandle at 2013-01-27 23:29:50
Interesting problem, what is the purpose of this? :slight_smile:
What surprises me is that you use hashtable instead of an array. Are there any reasons? Even creating list does not give you the absolutely correct result because some automatic variables are present only in some contexts, but I am pretty sure you are aware of this.
by MattG at 2013-01-28 02:34:58
I’m using a hashtable to take note of when I encounter a built-in variable in a script. A key-value pair is ideal in my scenario.

The reason I need this is because I’m doing some AST manipulation for a project I’m working on.
by nohandle at 2013-01-28 03:22:12
Thanks, for the explanation.
by DonJ at 2013-01-29 14:09:17
Matt, the underlying reason is that there aren’t really any built-in variables. That is, the engine itself doesn’t define them until a runspace is created, at which point they all look like user variables. It doesn’t differentiate.
by MattG at 2013-01-29 15:32:56
Agreed. After the runspace is created the engine doesn’t differentiate. I was merely interested in a programmatic way to differentiate the variables that PowerShell generates and those created by the user (e.g. $OFS vs. $foo). Oisin pointed me to a great non-public class that lays many of these variable out - System.Management.Automation.SpecialVariables. The following one-liner will generate the list for you:
[PSObject].Assembly.GetTypes() | ? { $.Name -eq ‘SpecialVariables’ } | % { $.GetFields(‘NonPublic, Static’) } | ? { $.FieldType -eq [String] } | % { "`$$($.GetValue($null))" }

Unfortunately, this class is only available in .NET 4.x. I’ll end my semantic rebuttal now. ;D