Tag Archives: Get-Variable

To Rename a PowerShell Variable

I had one of those thoughts…  you know, a dumb one. As dumb as it might be, it gave some brief inspiration to try something new. It seemed possible and easy enough and so I set out to prove, that as dumb (and useless), as it is, that it could be mine.

First off, on my machine, as it sits here today, I have 40 commands that include the “rename” verb. Additionally, I have five commands that include the “Variable” noun. Do you know what I do not have, though? I will tell you in a second if you have not figured it out yet. If you have figured it out, I will also tell you.

[PS7.2.1][C:\] Get-Command -Verb Rename | Measure-Object | Select-Object -Property Count

Count
-----
   40

[PS7.2.1][C:\] Get-Command -Noun Variable | Measure-Object | Select-Object -Property Count

Count
-----
    5

A Rename-Variable command. And you know why!? Because it is dumb and mostly useless. Regardless, I made it a thing and we will discuss it during this post. In the end, I think it turned out to be a success even though I will never use it again after today. That is what I say now, anyway.

Let’s do this in reverse. We will start with the commands I will invoke and then we will look at my function. My first below command Rename-Variable will send in the variable named TestVariableZero and the name to which we want to rename it, TestVariableZeroZero. This will not work, as we cannot rename a variable that does not yet exist. The function will use Write-Warning to inform us that it cannot be renamed. I could have used this section of the if-else to create the variable, but that is not today’s assignment. The next two lines will one, create the variable TestVariableOne with the value ValueOne and two, return information about the variable, so we know it has been created.

We are using the Force parameter in the first of these two commands in case the variable already exists. New-Variable cannot create a variable that already exists by default.

Rename-Variable -Name TestVariableZero -NewName TestVariableZeroZero

New-Variable -Name TestVariableOne -Value ValueOne -Force
Get-Variable -Name TestVariableOne

Rename-Variable -Name TestVariableOne -NewName TestVariableTwo

Get-Variable -Name TestVariableTwo
Get-Variable -Name TestVariableOne

Looking upward, we have three more commands to discuss. This Rename-Variable command will attempt to rename the TestVariableOne variable to TestVariableTwo. After that operation, we have two Get-Variable commands. The first will prove that we now have a TestVariableTwo variable and the second, that we no longer have a TestVariableOne variable. How fun right,… even though renaming a variable should not require its own command. With that, let’s take a look at the function.

function Rename-Variable {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory)]
        $Name,
        [Parameter(Mandatory)]
        $NewName
    )

    if (Get-Variable -Name $Name -Scope Global -ErrorAction SilentlyContinue) {
        Set-Variable -Name $NewName -Value (Get-Variable -Name $Name -ValueOnly -Scope Global) -Scope Global
        Remove-Variable -Name $Name -Scope Global
    }
    else {
        Write-Warning -Message "Unable to locate a variable with the name of $Name."
    }
}

You will be glad to know that not a lot of work went into writing this; it is very simple and very straightforward. Our function accepts two parameters: Name and NewName. Simple. We use Name to search for our existing variable and NewName to change its name. Notice the use of the -Scope Global parameter and parameter value. Without it, the variables that we would be working with inside the function would only be scoped to the function; they would not exist outside of the function. Providing the variable exists, we use Set-Variable inside the function to create a new/set an existing variable with the new name and take the value from the old variable and assign it as the value to the new variable. Once the new variable has been created and the old value assigned to it, we remove the previously named variable. Let’s try out the commands we saw at the beginning of this post.

Here is what happens when we try and rename a variable that does not exist.

[PS7.2.1][C:\] Rename-Variable -Name TestVariableZero -NewName TestVariableZeroZero
WARNING: Unable to locate a variable with the name of TestVariableZero.

So we can test out our function, let’s create our TestVariableOne variable and prove to ourselves that it has been created and that it now exists.

[PS7.2.1][C:\] New-Variable -Name TestVariableOne -Value ValueOne -Force
[PS7.2.1][C:\] Get-Variable -Name TestVariableOne

Name                           Value
----                           -----
TestVariableOne                ValueOne

Now, it is time to rename our variable from TestVariableOne to TestVariableTwo. The first command does just that. The next couple of commands proves that TestVariableTwo now exists with the proper value and TestVariableOne does not exist.

[PS7.2.1][C:\] Rename-Variable -Name TestVariableOne -NewName TestVariableTwo
[PS7.2.1][C:\] Get-Variable -Name TestVariableTwo

Name                           Value   
----                           -----   
TestVariableTwo                ValueOne

[PS7.2.1][C:\] Get-Variable -Name TestVariableOne
Get-Variable: Cannot find a variable with the name 'TestVariableOne'.

And that is it. If you are ever looking to rename a variable, using a built-in -Variable command, you are not going to find it. You can roll your own, however, if you really want to do that.

Scoping Out the Scope

Scope is awesome; it really is. In my mind, it is a protectionary layer to ensure things like variables are somewhat protected from say, modification. It can become a necessary concept for people using Powershell to understand. As I worked through some ideas recently, I ended up writing a function — this has been known to happen. As I sat there and fully comprehended what I had written, I began to realize that it may be worth sharing, so others can see it too. Sometimes we just need a simple example and a corresponding explanation. That has kind of been my goal over the years. Anyway, let’s focus on this function and I’ll explain what it is we have here and what it is doing.

The function is named, Get-TheVariable and it contains four commands and four comments, although two of those comments are just dashed lines. I don’t usually write comments anything like this, but I really want to break up the commands into two segments, to make sure I am as clear as I can be, as we walk through this, together. Those segments are the Global scope and the Local scope, but we will get to that soon enough. Down beneath the function are two separate commands separated by a semi-colon. The first command just clears the screen — because sometimes I need that to stay clear-headed — and the second invokes the Get-TheVariable function. Have a peek at the function now and then we will discuss it further below.

function Get-TheVariable {
    # Set and then get the GLOBAL version of the "Variable1" variable.
    # ----------------------------------------------------------------
    Set-Variable -Name Variable1 -Value 'G' -Scope Global -Description 'Scope:Global'
    Get-Variable -Name Variable1 -Scope Global | Select-Object -Property Name,Value,Description

    # Set and then get the LOCAL version of the "Variable1" variable.
    # ---------------------------------------------------------------
    Set-Variable -Name Variable1 -Value 'L' -Scope Local -Description 'Scope:Local/Function'
    Get-Variable -Name Variable1 -Scope Local | Select-Object -Property Name,Value,Description
}

Clear-Host; Get-TheVariable

So what is happening here? Before we go there, know something about how Set commands usually work. They work like New commands, unless whatever we are to trying to create already exists. In that case, they just make modifications.

The first two commands create, or modify a variable (if it already exists) and then return the variable. It is named “Variable1,” its value — like what it stores — is “G,” it is globally scoped, and it includes a description indicating that. It is created by the function, but not inside the function. It is created outside of the function, in the global scope.

The second two commands kind of do the same things, They create, or modify a variable (if it already exists) and then return the variable. It is named “Variable1,” its value — what it stores — is “L,” it is locally scoped, and it includes a description indicating that. It is also created by the function, but it is inside of the function. It is created inside of the function, in the local scope. While these variables have many things in common, such as their name, they are different.

In the end — and sorry for all the repetition — there are going to be two variables with the same name. This is perfectly okay since they are going to be created in different scopes. In real life, I would recommend not using the same name for variables even if they are scoped differently. For this example, and for fully understanding this concept, it is important we do it this way.

The below output is created by our function. In the first line, we have information about our globally scoped “Variable1” variable that was created by the function, outside of the function. Because it is globally scoped it is going to persist outside of the function. In the second line, we have information about our locally scoped “Variable1” variable that was created by the function, inside the function. Because it is locally scoped, it is not going to persist outside the function.

During the invocation of the function, the function’s scope is the local scope. When the function’s invocation is done and over, the local scope is the global scope (again). The local scope is always the current scope.

Name      Value Description
----      ----- -----------
Variable1 G     Scope:Global
Variable1 L     Scope:Function

When the function has ended, the locally scoped “Variable1” variable stops existing. The global version, however, is still alive and well. Let’s prove it.

Get-Variable -Name Variable1 -Scope Global | Select-Object -Property Name,Value,Description
Name      Value Description 
----      ----- ----------- 
Variable1 G     Scope:Global

In the above example, using -Scope Global was not necessary. Why? It’s because, again, we’re in the global scope and so there’s no need to tell the command to check a scope we are already in.

But, look at this.

Get-Variable -Name Variable1 -Scope Local | Select-Object -Property Name,Value,Description
Name      Value Description 
----      ----- ----------- 
Variable1 G     Scope:Global

What, the local variable still exists!? Uh, no, not the one created by the function for inside the function. This is kind of a recap — maybe the third or fourth one now, who knows. Again, now that we are outside of the function and back in the global scope, the Local parameter value returns the globally scoped variable, too. See the Value and Description properties? They are the same as the global variable because the local variable is the global variable when we are in the global scope.

I am beginning to think I should have left this topic to someone else. Read it a few times and if maybe I have confused you — ask questions, Read more on about_Scopes. I feel good about this post, I just likely need to read it like 10 more times and ensure it mostly makes sense.

I do want to mention this real quick because it comes up often, and good for you for reading this far; it may just pay off. If you are invoking a function and you reference a variable that has not been created or defined in the function, PowerShell will look for it outside of its local scope. That’s to say that it will go looking for the variable you didn’t assign, in the global scope, also known as the parent scope. And with the introduction of that new term, the function’s scope has another name, too. It is the child scope. Okay, I’m done. Hopefully, this didn’t confuse anyone. Phew.

PowerShell Variable Description Property

I don’t remember who mentioned it, but someone in the PowerShell community recently tweeted that they had been working with PowerShell for 10 years and had just learned something new. It wasn’t new to me, but I’m sure there are things out there I’ve yet to encounter. I sure hope so, anyway!

This individual didn’t realize that variables in PowerShell have descriptions. Did you know that!? Here are a few examples of different uses. Eventually, we’ll get to the description property, as well as all the properties you get every time you create a variable in PowerShell.

[PS7.1.5][C:\] $Variable = 'This is a string variable.'
[PS7.1.5][C:\]  $Variable
This is a string variable.
[PS7.1.5][C:\]
[PS7.1.5][C:\] Get-Variable -Name Variable -ValueOnly
This is a string variable.
[PS7.1.5][C:\]
[PS7.1.5][C:\] (Get-Variable -Name Variable).Value
This is a string variable.
[PS7.1.5][C:\]
[PS7.1.5][C:\] Get-Variable -Name Variable

Name                           Value
----                           -----
Variable                       This is a string variable.

[PS7.1.5][C:\] Get-Variable -Name Variable | Select-Object -Property *

PSPath        : Microsoft.PowerShell.Core\Variable::Variable
PSDrive       : Variable
PSProvider    : Microsoft.PowerShell.Core\Variable
PSIsContainer : False
Name          : Variable
Description   :
Value         : This is a string variable.
Visibility    : Public
Module        :
ModuleName    :
Options       : None
Attributes    : {}

[PS7.1.5][C:\]  

There it is… Description. Let’s add one and then return it!

[PS7.1.5][C:\] Set-Variable -Name Variable -Description 'This is the description property of a string variable.'
[PS7.1.5][C:\] (Get-Variable -Name Variable).Description
This is the description property of a string variable.

If you didn’t know this either, then just maybe this is exciting for you, too! I liked it when I first found it. I will link an old post below that I wrote about variable descriptions the first time around. It may be much of what was presented here already. There’s another post I wish I could find, but I think it was posted on another website and it has since been lost. Somebody on some forum wanted to know the last value that a variable contained and so I wrote a post about storing the variable’s previous value in the description property each time the variable was updated to something new. That’s was fun, and unique!

Give  your Variable a Description

A Variable’s Current and Previous Value

How to Store a Variable’s Previous Value with the New Value

There was a recent post on the PowerShell Facebook group that said this: “Is there a function or option to check previous $Global:variable -ne Current $Global:variable?” The person that created the post wanted to know if there’s a way to recall the last value a variable stored, once it had already been assigned something new. Here’s my answer, and potential solution.

You have to think about a variable’s previous assignment, as if it never existed, even though you know that variable held something, or was assigned something, previously. Once its value is gone, it’s gone. Now, all that said, I came up with an option. The option, is to use a variable’s description property to store its previous value.

Let’s begin by checking the value of an uninitialized variable, and then assign it something.

PS > $x
PS > # No value.
PS > $x = 'first value'
PS > $x
first value

Now that our variable has a value, let’s take a look at all the variable’s properties using the Get-Variable cmdlet. Notice the Description property; we’re going to use this in a less than conventional way.

PS > Get-Variable -Name x | Select-Object -Property *

Name        : x
Description :
Value       : first value
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

Using the Set-Variable cmdlet, we’ll make two modifications to our variable, at nearly the same time. First, we’ll update the Description property, so that it’s holding the original variable assignment (the string ‘first value’). In the same, Set-Variable command, we’ll modify the current value of the variable to the string ‘second value.’ Notice in the final below command, that our Description property has a value now, too.

PS > Set-Variable -Name x -Value 'second value' -Description $x
PS > $x
second value
PS > Get-Variable -Name x | Select-Object -Property *

Name        : x
Description : first value
Value       : second value
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

In the next example, you’ll see how we can return the original value and the variable’s updated value. Beneath that, I’ve included a couple ways to compare these values. That gets back to what the person on Facebook was trying to determine. Again, this is fairly unconventional use of the Description property, but it does avoid the need for a second variable to hold the first variable’s original value. That said, one of my examples uses a second, comparison variable.

PS > (Get-Variable -Name x).Description
first value
PS > (Get-Variable -Name x).Value
second value
PS > $x
second value

PS > (Get-Variable -Name x).Description -ne (Get-Variable -Name x).Value
True
PS > (Get-Variable -Name x).Description -ne $x
True
PS > $y = (Get-Variable -Name x).Description
PS > $y -ne $x
True

In these last examples, we’re running into a bit of a problem, we are going to have to keep in mind (if anyone even dares use this approach). When we take a value that isn’t a string, and place it into the Description property, it becomes a string. That means, that when we take it back out, we’ll need to cast it back to its proper type. Take a look at the next series of examples for some assistance with this concept.

PS > $z = 5
PS > Set-Variable -Name z -Value 10 -Description $z
PS > Get-Variable -Name z | Select-Object -Property *

Name        : z
Description : 5
Value       : 10
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

PS > (Get-Variable -Name z).Description | Get-Member |
>>> Select-Object -Property TypeName -Unique

TypeName
--------
System.String

PS > [int](Get-Variable -Name z).Description
5
PS > [int](Get-Variable -Name z).Description | Get-Member |
>>> Select-Object -Property TypeName -Unique

TypeName
--------
System.Int32

This goes for decimals values, too. If you use the Description property to store something that’s not a string, then you’re going to have to properly cast it when you’re taking it out, or you’re going to have a string. In these next examples, I used the GetType method to determine the value’s type, as opposed to Get-Member and Select-Object used above.

PS > $m = 2.5
PS > $m.GetType().Name
Double
PS > Set-Variable -Name m -Value 3.5 -Description $m
PS > $m
3.5
PS > $m.GetType().Name
Double
PS > (Get-Variable -Name m).Description
2.5
PS > (Get-Variable -Name m).Description.GetType().Name
String
PS > [double](Get-Variable -Name m).Description
2.5
PS > ([double](Get-Variable -Name m).Description).GetType().Name
Double

And that’s it. It’s may not be the first choice for saving a previous variable’s value, but it’s a choice. I rather liked the array option that was recommended; however, like the $Error array, I’d be tempted to put the newest/current value of a variable into index 0 and not at the end of the array. Anyway, back to real life now.

Bulk Remove Variables, Carefully

Ever have one of those situations where you need to remove, or perhaps reinitialize, a set of variables and have to deal with remembering them all? This doesn’t happen often, but there are times when I need to clear, or remove, variables between loop iterations. You either need to keep track of all your variable names, or — and I wouldn’t recommend this so much — do a Remove-Variable -Name *. While the help on PowerShell 5.1.14394.1000 (5.1 preview version), says that Remove-Variable doesn’t accept wildcards, it does, and I think it always has.

Let’s start with the below example. These few lines do the following: 1. Return the number of variables in the PowerShell session, 2. Add a new variable x, 3. Return the number of variables again, 4. Remove all the variables I can (some can’t be removed), 5. Return the number of variables again (again), and 6. See if I can return my variable x.

[tommymaynard@srv01 c/~]$ (Get-Variable).Count
51
[tommymaynard@srv01 c/~]$ New-Variable -Name x -Value 'string'
[tommymaynard@srv01 c/~]$ (Get-Variable).Count
52
[tommymaynard@srv01 c/~]$ Remove-Variable -Name * -ErrorAction SilentlyContinue
[tommymaynard@srv01 c/~]$ (Get-Variable).Count
29
[tommymaynard@srv01 c/~]$ Get-Variable -Name x
Get-Variable : Cannot find a variable with the name 'x'...

While we can do this to remove the variables we’ve created in the session, we end up removing variables that weren’t necessary to remove. We’re better than this.

In the next example, we’ll add a variable prefix “dog” to all of our variables. This will allow us to find all of the variables by prefix, and then delete just those. Not a bad idea really, but it wasn’t my first thought.

[tommymaynard@srv01 c/~]$ New-Variable -Name dog1 -Value 'string1'
[tommymaynard@srv01 c/~]$ New-Variable -Name dog2 -Value 'string2'
[tommymaynard@srv01 c/~]$ New-Variable -Name dog3 -Value 'string3'
[tommymaynard@srv01 c/~]$ Get-Variable -Name dog*

Name                           Value
----                           -----
dog1                           string1
dog2                           string2
dog3                           string3

[tommymaynard@srv01 c/~]$ Remove-Variable -Name dog*
[tommymaynard@srv01 c/~]$ Get-Variable -Name dog*
[tommymaynard@srv01 c/~]$ # No results, as they've been deleted.

Had I thought of the above option first, I might’ve just gone with that idea, but let me share what I was really thinking. It’s involves the description property. When we create our variables with New-Variable, we have the option to set more than just the Name and Value. Let’s take a look at the below example, and then discuss it.

[tommymaynard@srv01 c/~]$ New-Variable -Name a -Value 'stringA' -Description (Get-Date)
[tommymaynard@srv01 c/~]$ $StartDate = Get-Date
[tommymaynard@srv01 c/~]$ New-Variable -Name b -Value 'stringB' -Description (Get-Date)
[tommymaynard@srv01 c/~]$ New-Variable -Name c -Value 'stringC' -Description (Get-Date)
[tommymaynard@srv01 c/~]$ Get-Variable -Name a,b,c

Name                           Value
----                           -----
a                              stringA
b                              stringB
c                              stringC

[tommymaynard@srv01 c/~]$ Get-Variable -Name a,b,c | Select-Object Name,Value,Description

Name Value   Description
---- -----   -----------
a    stringA 11/03/2016 20:52:41
b    stringB 11/03/2016 20:53:05
c    stringc 11/03/2016 20:53:20

Now, it’s important to remember that a variable’s description property is a string. This means that when we put the current date in the property, it was converted to a string. That means that Thursday, November 3, 2016 20:53:20 PM became this: 11/03/2016 20:53:20. What we’ll need to do is convert it back to a datetime before we compare. We do that in the below example by casting the description property as a datetime object. If it’s not clear yet, our end goal is to remove variables that were created after a specific point in time.

[tommymaynard@srv01 c/~]$ Get-Variable -Name a,b,c | Where-Object {[datetime]$_.Description -gt $StartDate}

Name                           Value
----                           -----
b                              stringB
c                              stringC

We can also use the Get-Date cmdlet to do this, as well.

[tommymaynard@srv01 c/~]$ Get-Variable -Name a,b,c | Where-Object {(Get-Date -Format $_.Description) -gt $StartDate}

Name                           Value
----                           -----
b                              stringB
c                              stringC

Since we can now isolate the variables we created after a specific time, we can go ahead and blow them away. Here goes:

[tommymaynard@srv01 c/~]$ Get-Variable -Name a,b,c | Where-Object {(Get-Date -Format $_.Description) -gt $StartDate} | Remove-Variable
[tommymaynard@srv01 c/~]$ Get-Variable a,b,c

Name                           Value
----                           -----
a                              stringA
Get-Variable : Cannot find a variable with the name 'b'.
At line:1 char:1
+ Get-Variable a,b,c
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (b:String) [Get-Variable], ItemNotFoundException
    + FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand

Get-Variable : Cannot find a variable with the name 'c'.
At line:1 char:1
+ Get-Variable a,b,c
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (c:String) [Get-Variable], ItemNotFoundException
    + FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand

Well, that’s it for today. Now you can use description property of your variables to hold the time in which they were created. This will allow you to selective remove any of them based on a start time. I like it, although the whole prefix thing might be an easier option.

PSMonday #8: Monday, June 20, 2016

Topic: Less Used Variable Properties

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

When someone sets, or assigns, a variable in Windows PowerShell, we typically expect it to look a certain way, as is demonstrated below. This example also shows how we typically return a variable’s value, after it’s been assigned.

$String = 'Welcome back to Monday.' # Assign a value to variable.
$String # Return a variable’s value.

Welcome back to Monday.

This assigns, or sets, the variable named string, the value of ‘Welcome back to Monday.’ Straightforward, right? Well, this isn’t the only way to assign a variable in PowerShell. There’s a more formal process that offers a few extra options. When we use the *-Variable cmdlets, we don’t use the dollar sign ($). The dollar sign is only used to indicate to the PowerShell parser that what follows it, will be a variable name. The difference here is that these variable cmdlets already know you’re providing a variable name.

New-Variable -Name String2 -Value 'Come on, Friday.'
Get-Variable -Name String2

Name                           Value
----                           -----
String2                        Come on, Friday.

If you choose to use the Get-Variable cmdlet to return just the value, you can use the -ValueOnly parameter, dotted-notation, or Select-Object’s -ExpandProperty parameter. In older versions of PowerShell, dotted-notation may not be an option.

Get-Variable -Name String2 -ValueOnly
(Get-Variable -Name String2).Value
Get-Variable -Name String2 | Select-Object -ExpandProperty Value

Come on, Friday.
Come on, Friday.
Come on, Friday.

I’m not here to suggest variables should always be created with New-Variable, that values should always be returned with Get-Variable, that variables should always be updated with Set-Variable, or even that we should always clear or remove variables with Clear-Variable and Remove-Variable, respectively. What I’m out to do, is tell you about a couple extra properties that are attached to our variables, that you might not know about, and how we might use them.

Let’s modify the command we used to return the value of our $String2 variable, so we return all the properties. Keep in mind, that we can do the same thing with our $String variable that was created without the New-Variable cmdlet.

Get-Variable -Name String2 | Select-Object *

Name        : String2
Description :
Value       : Come on Friday.
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

Notice that we have a Description property and an Options property. The Description property is another way to provide additional meaning to a variable. While you should strive to name your variables in a way that describes their contents, if you’re feeling up to it, you can add additional information about the variable in this property.

Set-Variable -Name String2 -Description 'Demo purposes only'
(Get-Variable -Name String2).Description

Demo purposes only

Let’s talk about the Options property next week, as it’s a bit more useful.

Give your Variable a Description

When we think of variables in Windows PowerShell, we often only consider two parts: the name of the variable, and the value of the variable. Well, it turns out that those aren’t the only properties; let’s discuss the description property.

I can’t say I’ve ever added a description to a variable until now, but I can think of times, when looking at someone’s code, where I wish I knew the reason why a variable existed. Best practice would indicate we use meaningful names for our variables, so it’s probably safe to assume that the same people that might use a poorly-named variable, probably don’t know or care that variables can have descriptions… but, I digress.

In this first example, we’ll create a new variable using what I’d call the standard method — the equal sign assignment operator.

PS C:\> $a = 12345
PS C:\> $a
12345
PS C:\> Get-Variable a | Select-Object *

Name        : a
Description :
Value       : 12345
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

In line 1, we created a new variable, $a, and set its value to the numeric 12345. In the next line, we simply echoed the variable’s value. In line 4, we used the Get-Variable cmdlet and piped it to the Select-Object cmdlet and * so we were able to view all of its properties. If you take a look at the results, you’ll see the description property, and notice that it’s currently blank.

In the next example, we’ll use the Set-Variable cmdlet to modify the variable’s description.

PS C:\> Set-Variable a -Description 'This variable contains a 5-digit number.'
PS C:\> Get-Variable a | Select-Object *

Name        : a
Description : This variable contains a 5-digit number.
Value       : 12345
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

PS C:\>

Once we use the Get-Variable cmdlet, and return all the properties again, we can see that our variable now contains a description value. Now, while many user-defined variables, such as we created here, don’t often contain descriptions, many of the automatic and preference variables do — take a look at a segment of the results returned by the next command.

PS C:\> Get-ChildItem variable: | Select-Object Name,Description | Format-Table -AutoSize

Name                       Description
----                       -----------
...
MaximumAliasCount          Maximum number of aliases allowed in a session
MaximumDriveCount          Maximum number of drives allowed in a session
MaximumErrorCount          Maximum number of errors to retain in a session
MaximumFunctionCount       Maximum number of functions allowed in a session
MaximumHistoryCount        Maximum number of history objects to retain in a session
MaximumVariableCount       Maximum number of variables allowed in a session
MyInvocation
NestedPromptLevel          Dictates what type of prompt should be displayed for the current nesting level
...

Well, there you go: something you might not have known about, and something you may never use.

about_Variables

This post is the help rewrite for about_Aliases. While the help files for Windows PowerShell are invaluable, the idea behind a rewrite is so true beginners might even better understand the help file concepts. At times, some things discussed in the Windows PowerShell help file will not be included in a help rewrite. Therefore, it is always best to read the actual help file after reading this post. (PS3.0)

A variable in Windows PowerShell is a storage container in memory that can hold a value or values. Variables can store numbers, letters, strings (a sequence of numbers, letters, and/or other characters), and the results of a command that has been run in Windows PowerShell. Variables are defined by a dollar sign ($) and a string of text that follows.

PS C:\> $myVariable
PS C:\> $Process
PS C:\> $UserName
PS C:\> $a
PS C:\> $Var

Windows PowerShell has three types of variables. There are user-created variables, automatic variables, and preference variables. User-created variables are created by a user such as the variables in this example.

PS C:\> $Name = 'Macy Jones'
PS C:\> $Number = 10

Automatic variables store the state of Windows PowerShell, such as the $PSHOME variable, which stores the install location of Windows PowerShell. This type of variable cannot be changed by a user. This example shows what happens when a user tries to change the value of the $PSHOME automatic variable.

PS C:\> $PSHOME
C:\Windows\System32\WindowsPowerShell\v1.0
PS C:\> $PSHOME = 'C:\Windows'
Cannot overwrite variable PSHOME because it is read-only or constant.
At line:1 char:1
+ $PSHOME = ‘C:\Windows’
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (PSHOME:String) [], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotWritable

Preference variables store a default value but can be changed. These types of variables include the $MaximumAliasCount variable that stores the maximum number of aliases Windows PowerShell will store (the default value for this variable is 4096). This example shows how this variable’s value can be changed.

PS C:\> $MaximumAliasCount
4096
PS C:\> $MaximumAliasCount = 2000
PS C:\> $MaximumAliasCount
2000
PS C:\> $MaximumAliasCount = 4096

Variables are created by combining a dollar sign ($) and a text string. It is beneficial to name variables in such a way that the name helps define what the variable will store. Then use the = operator to assign, or set, the variable with a value. This example shows two variables, $Name and $Number, being set to two different values. To display the value assigned to a variable, type a dollar sign and the variable name and press Enter.

PS C:\> $Name = 'Macy Jones'
PS C:\> $Number = 10
PS C:\> $Series = 1,2,3
PS C:\> $Name
Macy Jones
PS C:\> $Number
10
PS C:\> $Series
1
2
3

The variable’s values can also be displayed using the Write-Output cmdlet, as well as the aliases for Write-Output, write and echo. This is used more often in scripts as opposed to the Windows PowerShell console.

PS C:\> Write-Output $Name
Macy Jones
PS C:\> write $Name
Macy Jones
PS C:\> echo $Name
Macy Jones

While the Write-Host cmdlet can also display a variable’s value, in most cases, it should not be used in place of Write-Output.

PS C:\> Write-Host $Name
Macy Jones

Variable names are not case-sensitive. The case of a variable name does not matter when it is assigned or used. This example also indicates how to assign a new value to a variable that already had a value.

PS C:\> $name
Macy Jones
PS C:\> $NAME
Macy Jones
PS C:\> $NamE
Macy Jones
PS C:\> $NAME = 'Lance Andrews'
PS C:\> $name
Lance Andrews
PS C:\> $name = 'Macy Jones'
PS C:\> $NAMe
Macy Jones

Variables can hold the results of commands. The first part of this example uses the Get-Process cmdlet to immediately display the first four running processes. In the second part of the example, the first four running processes are stored in a variable and then displayed when the variable is entered.

PS C:\> Get-Process | Select-Object -First 4

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    224      19     3436        772   110    16.80   4612 ALMon
    164      14     2476       2100    44     5.53   2744 ALsvc
     77       9     1336       5288    75   140.70   4076 ApMsgFwd
     90       8     1372       5852    76   162.11   4324 ApntEx

PS C:\> $Processes = Get-Process | Select-Object -First 4
PS C:\> $Processes

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    224      19     3436        772   110    16.80   4612 ALMon
    164      14     2476       2100    44     5.53   2744 ALsvc
     77       9     1336       5288    75   140.73   4076 ApMsgFwd
     90       8     1372       5852    76   162.11   4324 ApntEx

This examples sets, or assigns, the $Date variable to the results of the Get-Date cmdlet.

PS C:\> $Date = Get-Date
PS C:\> $Date

Thursday, May 01, 2014 9:20:30 PM

The Clear-Variable cmdlet, or clv alias, in this example, will remove the value that has been assigned to a variable without destroying, or removing, the variable itself. When referencing the variable, the dollar sign ($) is not used with either of these two cmdlets or with the Get-Variable cmdlet. The Get-Variable cmdlet will list all the variables in the session or list a single variable when a variable name is supplied.

PS C:\> $Name
Macy Jones
PS C:\> Clear-Variable Name
PS C:\> $Name
PS C:\> Get-Variable Name

Name                           Value
----                           -----
Name

The Remove-Variable cmdlet, or rv alias, in this example, will completely remove a variable and its stored value from memory.

PS C:\> $Color = 'Green'
PS C:\> $Color
Green
PS C:\> Remove-Variable Color
PS C:\> $Color
PS C:\>
PS C:\> Get-Variable Color
Get-Variable : Cannot find a variable with the name ‘Color’.
At line:1 char:1
+ Get-Variable Color
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Color:String) [Get-Variable], ItemNotFoundException
    + FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand

Variables can store different types of data. Normally they make their type determination based on the value(s) assigned to them. They can store integers, strings, arrays, and more. A single variable, when it is an array, can contain different types of data at the same time. The examples below use the Get-Member cmdlet to return properties (and more) about our variable. The Select-Object cmdlet has also been used to help filter what is returned.

PS C:\> $a = 12
PS C:\> $a | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.Int32

PS C:\> $a = 'Word'
PS C:\> $a | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.String

PS C:\> $a = 12,'Word'
PS C:\> $a | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.Int32
System.String

A variable can be forced to be a certain type by casting the variable. In the first part of the example below, the variable $Number will be cast with an int type (int, as in, integer). Even though the variable is cast as an integer, it is able to handle being assign a string value of “12345.” This is because the variable can change that string into a numeric value. It cannot do the same thing with the string “Hello.”

Further down in the example, the $Words variable has been cast as a string. When it is set to a numeric value it converts the numeric value into a string value. If the variable is used in a mathematical equation, such as an addition equation, it does not add the two values and instead will concatenate, or join them.

PS C:\> [int]$Number = 10
PS C:\> $Number
10
PS C:\> $Number = '12345'
PS C:\> $Number
12345
PS C:\> $Number = 'Hello'
Cannot convert value “Hello” to type “System.Int32”. Error: “Input string was not in a correct format.”
At line:1 char:1
+ $Number = ‘Hello’
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
PS C:\> [string]$Words = 'Hello'
PS C:\> $Words
Hello
PS C:\> $Words = 2
PS C:\> $Words
2
PS C:\> $Words + 10
210
PS C:\> $Number
12345
PS C:\> $Number + 10
12355

There are differences between using single quotes–which should be used as often as possible–and double-quotes. Single quotes around a variable will not expand the value stored in the variable; however, using double quotes will expand the variable.

PS C:\> $Name = 'Macy Jones'
PS C:\> 'Her name is $Name'
Her name is $Name
PS C:\> "Her name is $Name"
Her name is Macy Jones

Although variable names can include spaces and special characters, it should be avoided as it can quickly lead to confusion. Using spaces and special characters requires the variable name be enclosed in curly brackets {}.

PS C:\> ${!@#$} = 'Monday'
PS C:\> ${Favorite Day} = 'Friday'
PS C:\> ${!@#$}
Monday
PS C:\> ${Favorite Day}
Friday

Windows PowerShell creates a variable drive that looks and acts a lot like a file system drive. You can access data in the variable drive the same way things are accessed in a file system. The first example uses Get-ChildItem to get the first 4 folders in C:\Windows. The second example does the same thing but instead returns the first four variables in the variable drive.

PS C:\> Get-ChildItem C:\Windows | select -First 4

    Directory: C:\Windows

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         11/5/2013   3:31 PM            ADAM
d----         7/13/2009  10:32 PM            addins
d----         7/13/2009   8:20 PM            AppCompat
d----         4/11/2014   5:22 PM            AppPatch

PS C:\> Get-ChildItem variable:\ | select -First 4

Name                           Value
----                           -----
!@#$                           Monday
$                              4
?                              True
^                              Get-ChildItem

The only other variable cmdlet that was not discussed is the New-Variable cmdlet. This cmdlet is often not used since a variable can be created without it. The first example below shows how to return all the variable-related cmdlets. The second example shows how to use New-Variable.

PS C:\> Get-Command *-Variable

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Clear-Variable                                     Microsoft.PowerShell.Utility
Cmdlet          Get-Variable                                       Microsoft.PowerShell.Utility
Cmdlet          New-Variable                                       Microsoft.PowerShell.Utility
Cmdlet          Remove-Variable                                    Microsoft.PowerShell.Utility
Cmdlet          Set-Variable                                       Microsoft.PowerShell.Utility

PS C:\> New-Variable -Name DaysInYear -Value 365
PS C:\> $DaysInYear
365

Bonus Information

There may come a time when two (or more) variables need to be set to the same value. These do not need to be set individually. This first example shows how to set two variables at the same time and the second example shows how to set three variables at the same time.

PS C:\> $a = $b = 'Windows PowerShell'
PS C:\> $a
Windows PowerShell
PS C:\> $b
Windows PowerShell
PS C:\> $x = $y = $z = 42
PS C:\> $x
42
PS C:\> $y
42
PS C:\> $z
42

Real World

When values of a variable are displayed in the console, it will very rarely follow the Write-Output cmdlet. This cmdlet is most often used in scripts than it is with commands written in the console.

Learn More

This information, and more, are stored in the help file about_Variables that comes with Windows PowerShell. This information can be read by typing any of the commands below. The first example will display the help file in the Windows PowerShell console, the second example will open the full help in its own window, and the third example will send the contents of the help file to the clipboard (so it can be pasted into Word, Notepad, etc.), and the fourth example will open the help file in Notepad.

PS C:\> Get-Help about_variables
PS C:\> Get-Help about_variables -ShowWindow
PS C:\> Get-Help about_variables| clip
PS C:\> Notepad $PSHOME\en-us\about_Variables.help.txt