As you might imagine I write a lot of PowerShell scripts and examples. Often my PowerShell Window is open for days at a time. One challenge I have always has is trying to remember what variables I have defined. If I knew the name I'd simply use Get-Variable. What I really want is a way to see just the variables that I've created. So I wrote a function to do just that. As an added benefit I can also export these variables and re-import them into another PowerShell session.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Here's the function's core code, less the comment based help.
[cc lang="PowerShell"]
Function Get-MyVariable {
[cmdletbinding()]
Param(
[Parameter(Position=0)]
[ValidateSet("Global","Local","Script","Private",0,1,2,3)]
[ValidateNotNullOrEmpty()]
[string]$Scope="Global")
if ($psise)
{
Write-Warning "This function is not designed for the PowerShell ISE."
}
else
{
Write-Verbose "Getting system defined variables"
#get all global variables from PowerShell with no profiles
$psvariables=powershell -noprofile -COMMAND "& {GET-VARIABLE | select -expandproperty name}"
Write-Verbose "Found $($psvariables.count)"
#find all the variables where the name isn't in the variable we just created
#and also isn't a system variable generated after the shell has been running
#and also any from this function
Write-Verbose "Getting current variables in $Scope scope"
$variables=Get-Variable -Scope $Scope
Write-Verbose "Found $($variables.count)"
Write-Verbose "Filtering variables"
#define variables to also exclude
$skip="LastExitCode|_|PSScriptRoot|skip|PSCmdlet|psvariables|variables|Scope"
$variables | Where {$psvariables -notcontains $_.name -AND $_.name -notmatch $skip}
Write-Verbose "Finished getting my variables"
}
} #end function
[/cc]
As I was developing this function, Get-MyVariable, I originally was focused on the global scope. But then I realized I could also use something like this to track variables defined in a script or function. Thus the function includes a parameter called -Scope with a default value of Global. You can use any of the parameters that you would use with any of the Variable cmdlets, ie Global, Local, Script or Private. You can also use an integer to indicate the scope level. A value of 0 means the current scope. A value of 1 is the parent scope, 2 is the next scope up and so on. I limited my function to 5 which should be more than enough. What this means is that I can run a command like this and check the state of all my variables.
[cc lang="PowerShell"]
PS C:\> function foo { . s:\get-myvariable.ps1;$a=4;$b=2;$c=$a*$b;get-MyVariable -scope 1 -verbose;$c}
[/cc]
The Get-MyVariable function has it's own scope so by specifying a scope of 1 I get the variables defined in the foo function.
[cc lang="PowerShell"]
PS S:\> foo
VERBOSE: Getting system defined variables
VERBOSE: Found 49
VERBOSE: Getting current variables in 1 scope
VERBOSE: Found 27
VERBOSE: Filtering variables
Name Value
---- -----
a 4
b 2
c 8
VERBOSE: Finished getting my variables
8
[/cc]
The function works by launching a separate PowerShell console session without any profiles to capture all variables. This should be all the variables defined by PowerShell. All I want is an array of the variable names.
[cc lang="PowerShell"]
$psvariables=powershell -noprofile -COMMAND "& {GET-VARIABLE | select -expandproperty name}"
[/cc]
Then all I have to do is get variables from the specified scope and filter out those that aren't from PowerShell as well as those defined in the Get-MyVariable function.
[cc lang="PowerShell"]
$variables=Get-Variable -Scope $Scope
#define variables to also exclude
$skip="LastExitCode|_|PSScriptRoot|skip|PSCmdlet|psvariables|variables|Scope"
$variables | Where {$psvariables -notcontains $_.name -AND $_.name -notmatch $skip}
[/cc]
The script containing this function also defines an alias, gmv. You can comment out if you don't want to use it. I've added this function to my profile. Now, if I need to "move" variables between sessions or even computers, I can export them to an XML file.
[cc lang="PowerShell"]
PS C:\> Get-MyVariable | Export-Clixml myvar.xml
[/cc]
You can then import this xml file in another session to restore these variables. This assumes you are only worried about global variables in your console session.
[cc lang="PowerShell"]
PS C:\> import-clixml f:\files\myvar.xml | foreach {set-variable -Name $_.name -Value $_.value}
[/cc]
One caveat: depending on your variables your XML file could get quite large. During testing I had a variable defined like this.
[cc lang="PowerShell"]
$evt=Get-Eventlog -list
[/cc]
My XML file was over 17MB in size.
One final note is that this function is designed to work with the PowerShell console, not the ISE. In fact, I have code to check if you are running it in the ISE. The varaiable, $psise, refers to the ISE object.
[cc lang="PowerShell"]
if ($psise)
{
Write-Warning "This function is not designed for the PowerShell ISE."
}
[/cc]
The ISE introduces it's own set of default variables. But since I primarily use the console, I didn't bother finding an easy way to filter them out. Feel free to work out that for yourself.
You can download the script file with my Get-MyVariable function here..
I ran into the same need to keep track of the variables I created, and added the following to my profiles (console and ISE):
$sysvars = gci variable: |% {$_.name}
$sysvars += “sysvars”
function my_vars {
gci variable: |% {$_.name} |? {$sysvars -notcontains $_}
}
I had to add sysvars after the fact because it didn’t exist yet when I did the gci.