If you have to debug a PowerShell script, it is helpful to display all its variables with their values. In complex scripts, you can also search in all your variables. With the help of the Get-Variable cmdlet and a little piping, you can easily remove PowerShell’s automatic variables from your list. The little function introduced in this post also allows you to easily remove all variables that you added to your consoles after you started the PowerShell session.

In my last two posts, I explained the different options to create a variable and how to deal with variable scopes. Today, I will show you how you can use the Get-Variable cmdlet to debug your PowerShell scripts.

Whenever a script is not doing what it is supposed to do, you’ll want to know the values of your variables. The Get-Variable cmdlet allows you to display the values of all variables in your current console. However, if you want to use the cmdlet to debug your scripts, you face two problems.

First, Get-Variable also displays all so-called automatic PowerShell variables. They are comparable to environment variables in Windows, and they store useful information about your PowerShell session. Just enter Get-Variable or, alternatively, dir variable: on a PowerShell console to get a list of the automatic variables:


Displaying automatic variables with Get-Variable

Displaying automatic variables with Get-Variable

Note that you can’t access PowerShell’s automatic variables in Windows (command prompt, Explorer, etc.). Because quite a few automatic variables exist, it is difficult to find your own variables in the list.

Second, as soon as your PowerShell script ends, PowerShell will drop all scopes that your script creates, along with all your variables. Thus, by default, the list that Get-Variable generates won’t contain the variable values from a previously executed script.

Making script variables available on the console ^

Let’s tackle the second problem first. One way to solve the problem is to use the debug features of PowerShell ISE. You can set a Toggle Breakpoint in a certain line by pressing F9. When you then run the script with F5, PowerShell ISE will pause at the Toggle Breakpoint. To view the contents of a variable, you simply have to hover with the mouse pointer over its name in the script.

This is certainly useful, especially because you can access the variable values after your script reaches the designated line. In contrast to the PowerShell console, PowerShell ISE also stores all script-level variables in the Global scope, which allows you to display them with Get-Variable at the prompt after the script terminates.

However, debugging in PowerShell ISE also has its problems. PowerShell ISE sometimes behaves differently than the PowerShell console does; in those cases, you will want to debug on a PowerShell host that behaves exactly like your production environment does. Another problem with this solution is that you don’t get an overview of all your variables.

To get a list of all your variables on the PowerShell console, you first have to ensure that they are still available after your script completes. The simplest way to do this is to dot source your script by launching it with a preceding dot and space:

. .\myScript

This will ensure that all variables in the Script scope will be available on the console (Global scope) after the script completes. However, this does not include variables that you use in functions. One way to access these variables is to call the function right from the console in dot source notation:

. myFunction

Because we dot sourced the script, all variables from the Script scope are available on the console, and the function should behave as if you called it at the end of the script. If you want to know the values of the variables in the function at another position in your script, you can terminate the script with the exit keyword. For instance, you can exit the script right after you call the function in your script:


If you then call the function dot sourced on the console, the variables are available in the Global scope. This procedure might not always be practical with complex functions and many parameters, and it might not always work in complex scripts that call a function several times.

A more reliable way is to dot source the function that interests you in the script. This way, its variables will be available on the console after the script terminates. If you are only interested in a few variables within a function, you can also temporarily change the scope to Global:


Note that, whenever you dot source a function or work with global variables, you had better ensure that you don’t use the same variable names at the script level or in other functions; if you do so, your script might then produce different results.

Excluding automatic variables in Get-Variable ^

After all variables are available on the console, you have several options to access their values. If you just want to know the value of a particular variable, you can just enter it on the console. As mentioned above, you can use the Get-Variable cmdlet to display all variables. However, the list will contain all automatic variables, which makes it hard to get an overview of your variables in the script.

One way to exclude the automatic variables from the list is to compare the output of the Get-Variable cmdlet before and after you call the script. If you often debug on the PowerShell console, you could add the following lines to your profile:

$AutomaticVariables = Get-Variable
function cmpv {
    Compare-Object (Get-Variable) $AutomaticVariables -Property Name -PassThru | Where -Property Name -ne "AutomaticVariables"

In the first line, we use the $AutomaticVariables variable to save the state of the variable list when you launch a PowerShell session. Next, we define a function that allows you to compare the new state of your console with the old sate. The Get-Variable cmdlet returns an array of PowerShell variable objects. With the Compare-Object cmdlet, we compare those two arrays.

The first argument for Compare-Object is (Get-Variable), which gives us the new state of our variables. The parentheses are needed to process the cmdlet’s output in the command rather than display it right away. The next argument is the $AutomaticVariables variable that stores the old state. To compare the two arrays, we use the Name property of the variable objects. Because the Compare-Object cmdlet does not generate output, we need the PassThru parameter. The result of the array comparison is then piped to the Where-Object cmdlet, where we remove our $AutomaticVariables variable. If we don’t do this, this variable would always appear in the variable list.

After you add the above commands to your PowerShell profile and restart your PowerShell console, you will have a new command that goes by the name cmpv. You can use it to display only the variables that have been added to your console after you launched it. Thus, when you launch a dot sourced script, cmpv will only display the variables that your script created in the Global scope.

Display variables you added after you launched the PowerShell console

Displaying variables you added after you launched the PowerShell console

If you launch your script a second time, you should remove all variables of the previous run from the console. The variables are now in the Global scope, and your script would use their values. You can now easily remove the script variables from the console with the following command:

cmpv | rv

Removing all new variables from the console

Removing all new variables from the console

We are piping all the variables that have been created in the Global scope since we launched the console to the Remove-Variable cmdlet, which has the alias rv. Essentially, the command above resets your console to the state when you launched it. Thus, the cmpv function is useful not only for debugging but also to clear your console from all variables except for the automatic variables.

By the way, if you don’t want to dot source your script, you can simply call the cmpv function at the end of your script. You can also call it within a function in your script if you only want to display all the variables of your function. This works because, by default, Get-Variable gets the variables from the current scope, which is the scope of the function if you call cmpv within the function.

Searching in variable names and values ^

Even though we removed all automatic variables with the cmpv function, the list might still be too long if you are debugging a complex script. With the following command, you can search for a certain term in all variables:

Get-Variable | Select Name,Value | Select-String "search term"

Searching in variable names and values

Searching in variable names and values

The result is an array because Get-Variable produces an array of variable objects. The Select-Object cmdlet creates a new array with custom PowerShell objects that only contain the Name and Value properties of the original PSVariable objects. Select-String then selects those array members that contain our search string in the variable’s name or in its value and creates a list of MatchInfo objects. The list includes automatic variables, but we already know how to get rid of them.

Searching in variables without automatic variables

Searching in variables without automatic variables

If you only want to search in the values of your variables, this is the command you need:

Get-Variable | Where {$_.Value -like "*search term*"}

Or, alternatively:

cmpv | Where {$_.Value -like "*search term*"}

Searching in variable values

Searching in variable values

A more human-readable version, without the usage of a script block (the expression in curly braces) and the $_ pipeline placeholder, is this command:

Get-Variable | Where Value -like "*search term*"

It does exactly the same thing as the previous command. If you omit the wildcards (*), the search will only match if the value of the variable is identical to the search term. Of course, you can use any other comparison operator for your search.

In the next and final part of my PowerShell variable series, I will discuss the properties of the PSVariable object.

Articles in series

The PowerShell variable

  1. Andy 5 years ago

    I improved your script by making use of the function scope…

    function Get-ScriptVariables {
        param (
            [ValidateScript( { Test-Path $_ } )]
        # save all variables in the local scope for compariso
        $locals = get-variable -scope local
        # execute the target script by dot sourcimg into the current scope
        . $Path #| Out-Null # pipe the output to null so that it doesnt alter our output
        # pass a new instance of the Get-Variable output along with the
        # saved $locals into the Compare-Object commandlet.  We also
        # exclude the $locals variable from the final output.
        Compare-Object -ReferenceObject (Get-Variable -scope local) -DifferenceObject $locals `
            -Property Name -PassThru | 
            Where-Object -Property Name -ine 'locals' | 
            Select-Object -Property @(
                    n = 'Type'
                    e = { $_.Value.GetType() }

    • Author

      Thanks! Works nicely.

      • Ramon Tan 4 years ago

        Dear Mr Pietroforte,

        I am enjoying your 4 articles on PS variables.

        In the 3rd article, on using the Get-Variable cmdlet for debugging, there are sections in which ‘cmpv’ is printed as ‘cpmv’.  I was a bit confused, but conclude that in the narrative text, it must be a misspelling or typographical error.  I based it on the fact that the screenshots accompanying the explanations all displayed ‘cmpv’.

        I would appreciate a quick confirmation if my ‘guess’ is correct.

        Sincere thanks.

  2. Anil Kushwaha 3 years ago

    Hi Michael,

    I want to print what statement is passed in a variable. Is it possible ?

    For Example: $a = Get-Content -Path 'C:\Temp\Abc.txt'

    So I want to print 'Get-Content -Path 'C:\Temp\Abc.txt' not the output of Abc text file.

    Is that possible ?

    • Leos Marek (Rank 4) 3 years ago
      $a = 'Get-Content xxxx'

      Like this. You need to put the command to '' and then it is saved to the variable as a text.


    • Author

      The thing is that when PowerShell reads the command it stores the value in the variable not the statement. What exactly do you want to do?

Leave a reply to Andy Click here to cancel the reply

Please enclose code in pre tags

Your email address will not be published.


© 4sysops 2006 - 2022


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account