- Author and member of the year 2019 – Why DevOps still doesn't rule the IT world - Wed, Jan 1 2020
- Results of the 4sysops member and author competition in 2018 - Tue, Jan 8 2019
- Why Microsoft is using Windows customers as guinea pigs - Reply to Tim Warner - Tue, Dec 18 2018
In my last post, where I demonstrated how you can use the Get-Variable cmdlet to debug your PowerShell scripts, I mentioned the PSVariable object. Today, I will take a closer look at this important PowerShell object, and we’ll discover what things we can do with it.
The PSVariable object ^
In most cases, when you interact with a variable, you will precede the variable name with the dollar sign, which tells the shell to read the variable’s value. However, the value is just one of several properties of the variable object. In the following example, we display all the properties of a variable object:
$myVariable = "Variables are objects."
Get-Variable myVariable | Select *
In the second command, we select all of the variable’s properties, including the hidden ones (properties that are not displayed by default).
Displaying all properties of a PSVariable object
Note that other variable object types exist. You can use the following command to get a list of variable types available in the variables of your current scope:
Get-Variable | Get-Member | Select TypeName -Unique
Variable descriptions ^
It won’t surprise you that the variable Name is another object property. The Description property can be useful if you want to document the purpose of a variable. The advantage over documenting in comments in your script is that you can easily see the descriptions of all variables that you list.
To store a Description in a variable, you use the Set-Variable cmdlet:
Set-Variable -Name myVariable -Description "My variable description"
You can also assign a Description when you create the variable with the New-Variable cmdlet:
New-Variable -Name myVariable -Value "Variables are objects" -Description "My variable description"
To view the Description of a particular variable, you can use the Get-Variable cmdlet, as in the first example in this post. This works, too:
$myVariable = "Describe your variables"
$myVariableObject = Get-Variable myVariable
$myVariableObject.Description = "My variable description"
Setting a description for a variable
To display the variables with their descriptions in your current PowerShell session, you can run this command:
Get-Variable | Select Name,Value,Description
The command above displays all the variables that you created on your console in addition to the automatic variables that PowerShell has set on your host. This gives you a quick overview of the purpose of each of the automatic variables.
To display only your own variables with their descriptions, you have to follow the instructions in my previous post and create the cmpv function in your profile. You can then display all your own variables, along with their description, this way:
cpmv | Select Name,Value,Description
Variable visibility ^
The Visibility property of a PowerShell variable can have the values Public or Private. Public is the default. Don’t confuse this property with the Private scope. The Visibility property allows a developer of a PowerShell module to hide variables. If you import a module with variables where Visibility is set to Private, you can’t view or change the variable on the console even if it is in the Global scope. If you try to access a Private variable, PowerShell will throw an error message: Cannot access the variable '$myPrivateVariable' because it is a private variable.
New-Variable -Name myPrivateVariable -Value "This is really private." -Visibility "Private"
Error message when trying to access a Private variable
Variable options ^
Another useful variable property is Options. Five valid values exist for this property: AllScope, Private, Constant, ReadOnly, and None. None is the default configuration.
I already discussed AllScope in my post about variable scopes. A variable where this option is set is available in all new child scopes. Private does the opposite; the variable will only be available on the current (Local) scope. This has the same effect as if you declare the variable as Private when you initialize it:
$Private:myPrivateVariable = "I value my privacy."
New-Variable -Name myPrivateVariable -Value "I value my privacy." -Option Private
Get-Variable myPrivateVariable | Select *
Different ways to set a variable as Private
These two commands accomplish the same thing. If you run one after the other, PowerShell will complain that you keep repeating yourself.
The Options properties Constant and ReadOnly have a similar effect: you can protect a variable from being overwritten with a new value. Protecting your variable with Constant is just a bit more reliable. You can delete a ReadOnly variable, and you may also override it by using the -Force parameter. A Constant variable cannot be changed at all, and you can only destroy it by ending your PowerShell session.
New-Variable -Name myReadOnlyVariable -Value "Please don't change me!" -Option ReadOnly
$myReadOnlyVariable = "I want to change you."
Set-Variable -Name myReadOnlyVariable -Value "I really need to change you." -Force
Remove-Variable myReadOnlyVariable -Force
Changing a ReadOnly Variable
Note that you cannot change the Options property of a ReadOnly variable. You first have to delete and then re-create it. The following examples demonstrate that Constant variables are truly constant:
New-Variable -Name Pi -Value 3.14 -Option Constant
Set-Variable -Name Pi -Value 3.141 -Force
Remove-Variable Pi -Force
Trying to change and delete a Constant variable
You are probably wondering why you would want to use ReadOnly and Constant variables if it causes so much trouble to change them. In programming languages that have to be compiled, the declaration of constants allows for compilation optimization; this is of no help in PowerShell because it is an interpreted language.
However, you can see ReadOnly and Constant variables as additional variable types. Type safety improves the reliability of your scripts. If you know that the value of a variable should not be changed in the entire script, you can set it to ReadOnly; if you are sure that a variable must not be changed, you can you set it to Constant. It is often better to allow a script to terminate with an error message rather than move ahead with the wrong variable values. Furthermore, if you work on a large project with other PowerShell developers, clarifying how a variable should be treated will improve the readability of your code.
ReadOnly and Constant variables can also be helpful when you are working at a PowerShell prompt. For instance, if you defined variables in your profile to save yourself from typing complex arguments, you might want to prevent Global variables in a script from accidentally overriding your variables.
Variable attributes ^
Variable attributes allow you to restrict the value of a variable. In a way, this enables you to create your own variable types. For example, you can restrict the range of an integer variable or limit the length of a string. The purpose is to make your script more reliable. This feature also allows you to validate user inputs. Of course, you can achieve the same results by validating the contents of a variable in your script. However, if you store the restrictions in the variable’s Attributes property, you ensure that its value will always meet your requirements.
Variable attributes are saved as an array in the PSVariable object, which enables you to assign multiple attributes to a variable. A variable attribute is an object by itself that you can create with the New-Object cmdlet. Object type names of variable attributes start with “System.Management.Automation.” The table below lists the abbreviated object type names that you can use to validate variables:
|Type Name (Abbreviated)||Purpose|
|ValidateNotNullOrEmptyAttribute||Not zero or empty|
So, for instance, the complete type name for configuring a number range is System.Management.Automation.ValidateRangeAttribute. In the following example, we restrict the values of an integer to the range 1-9:
[Int]$Number = Read-Host "Enter a number in the range 1-9"
$Attribute = New-Object System.Management.Automation.ValidateRangeAttribute -ArgumentList 1,9
Restricting a number to the range 1-9
In the above example, I entered the number 10, and PowerShell answered with an error message because the number is not in the specified range. If you want to prevent the error message, this little script shows how:
Function ValidateAnswer ($Answer)
$Attribute = New-Object System.Management.Automation.ValidateSetAttribute -ArgumentList Yes,No
$Answer = Read-Host "Do you want to continue, yes or no?"
ValidateAnswer($Answer) -Errocation Stop
Write-Host "Thank you! Good choice!"
Write-Host "Come on, I asked yes or no!"
This script asks for user input and only accepts “yes” or “no” as an answer. If you enter anything else, the script will ask again. Admittedly, easier ways exist to accomplish this task, but I think you now have an idea of how you can use variable attributes.
Validating user input
This concludes my variable series. I didn’t discuss everything that can be said about PowerShell variables, but I think you now know the most features.