Introduction to Microsoft PowerShell – Variables
There are several types of variables this are:
- User Created – These variables are the ones we create in the shell and in scripts. This variables are present only in the current process we are on and are lost when we close the session. We can create variables in scripts with global, script, or local scope.
- Automatic – These variables keep the state of the PowerShell session and can not be modified directly. The values of this variables change as we execute and use the PowerShell session. This variables will save last run state of cmdlets, commands as well as other objects and information.
- Preference – These variables store user preferences for PowerShell. These variables are created by PowerShell when a session is started and are populated with default values. We can change the values of these variables. For example, MaximumHistoryCount that sets the maximum number of entries in the session history.
- Environment – These variables are the variables set by the system for Command and PowerShell environments.
Creating and Accessing Variables
In PowerShell variables behave a bit differently than from what we are used to in other shell environments. We will see that do to the the unique way that PowerShell treats everything as an object variables are treated like so. Variable in PowerShell in reality are units of memory where we store values. Variables start with the symbol $ and followed by a string of letters like:
$this_is_a_variable
The string of letters and characters must be continuous and I recommend as a best practice to use descriptive names for the variables, you can use a mix of camel case where each word is capitalized or separate each work with a underscore as the example above.
Variables in PowerShell are not case sensitive and they may contain any letter, number and special character. When special characters are used they need to be enclosed in {}:
PS
C:\Users\Carlos\Desktop> ${this is an actual var of var's} = 10PS C:\Users\Carlos\Desktop> ${this is an actual var of var's}10
To assign a value to a variable we have 3 methods in PS. The first one is by just setting a name and using the = sign and providing any value we want to set:
$var1 = 1
We can also use the the New-Variable cmdlet:
New-Variable -Name var3 -Value "hello" -Description "Sample string variable"
As we can see the cmdlet provide us with the largest amount of options. Lets look at the the help for it:
PS C:\Users\Carlos\Desktop> help New-Variable NAME New-Variable SYNOPSIS Creates a new variable. SYNTAX New-Variable [-Name] <string> [[-Value] <Object>] [-Description <string>] [-Force] [-Option {None | ReadOnly | Constant | Private | AllScope}] [-PassThru] [-Scope <string>] [-Visibility {Public | Private}] [-Confirm] [-WhatIf] [<CommonParameters>] DESCRIPTION The New-Variable cmdlet creates a new variable in Windows PowerShell. You can assign a value to the variable while creating it or assign or change the value after it is created. You can use the parameters of New-Variable to set the properties of the variable (such as those that create read-only or constant variables), set the scope of a variable, and determine whether va riables are public or private. Typically, you create a new variable by typing the variable name and its value, such as "$var = 3", but you can use the New-Variable cmdlet to use its parameters. RELATED LINKS Online version: http://go.microsoft.com/fwlink/?LinkID=113361 Get-Variable Set-Variable Remove-Variable Clear-Variable REMARKS To see the examples, type: "get-help New-Variable -examples". For more information, type: "get-help New-Variable -detailed". For technical information, type: "get-help New-Variable -full".
As we can see it provides a lot of flexibility when creating the variable. The Se-Variable cmdlet can also be used and has a similar list of options as the New-Varibale cmdlet with some slight differences, like the ability to pass the variable content with the –PassThru parameter to the pipe to be consumed by another cmdlet.
When we want to get the value of a variable we can just type the variable name in the shell and hit enter. We can also use the Get-Variable cmdlet:
PS C:\Users\Carlos\Desktop> $var1 = 1 PS C:\Users\Carlos\Desktop> $var1 1 PS C:\Users\Carlos\Desktop> Get-Variable -Name var1 Name Value ---- ----- var1 1
One thing to keep in mind is that as we covered in previous blog post variables are also available as a PSDrive so we can treat them also as a file system. If we want to get a listing of all variable we would use the Get-Variable cmdlet with no parameters we can also do a Dir of the PSDrive:
PS C:\Users\Carlos\Desktop> dir variable: Name Value ---- ----- $ variables: ? False ^ dir _ args {} ConfirmPreference High ConsoleFileName DebugPreference SilentlyContinue Error {Cannot find drive. A drive with the name 'variables' does not exist., Cannot find drive. A drive with the name 'variables' does not exist., Cannot find drive. A dri... ErrorActionPreference Continue ErrorView NormalView ExecutionContext System.Management.Automation.EngineIntrinsics false False FormatEnumerationLimit 4 HOME C:\Users\Carlos Host System.Management.Automation.Internal.Host.InternalHost input System.Collections.ArrayList+ArrayListEnumeratorSimple LASTEXITCODE 0 MaximumAliasCount 4096 MaximumDriveCount 4096 MaximumErrorCount 256 MaximumFunctionCount 4096 MaximumHistoryCount 64 MaximumVariableCount 4096 MyInvocation System.Management.Automation.InvocationInfo NestedPromptLevel 0 null OutputEncoding System.Text.ASCIIEncoding PID 6648 PROFILE C:\Users\Carlos\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 ProgressPreference Continue PSBoundParameters {} PSCulture en-US PSEmailServer PSHOME C:\Windows\System32\WindowsPowerShell\v1.0 PSSessionApplicationName wsman PSSessionConfigurationName http://schemas.microsoft.com/powershell/Microsoft.PowerShell PSSessionOption System.Management.Automation.Remoting.PSSessionOption PSUICulture en-US PSVersionTable {PSVersion, PSCompatibleVersions, BuildVersion, PSRemotingProtocolVersion...} PWD C:\Users\Carlos\Desktop ReportErrorShowExceptionClass 0 ReportErrorShowInnerException 0 ReportErrorShowSource 1 ReportErrorShowStackTrace 0 ShellId Microsoft.PowerShell srvs {System.ServiceProcess.ServiceController, System.ServiceProcess.ServiceController, System.ServiceProcess.ServiceController, System.ServiceProcess.ServiceController...} StackTrace at System.Management.Automation.PropertyReferenceNode.SetValue(PSObject obj, Object property, Object value, ExecutionContext context) test hello true True var1 1.3 var2 20 VerbosePreference SilentlyContinue WarningPreference Continue WhatIfPreference False
To get the contents of a variable when using the PSDrive Method we would use the Get-Content cmdlet just like we would with a file:
PS
C:\Users\Carlos\Desktop> Get-Content Variable:\PSHOMEC:\Windows\System32\WindowsPowerShell\v1.0
When we want to know what type of value we have in a variable we can use the the .GetType() method and we can get the property of .Name to see the name of the type or use .FullName to get the .Net type.
PS C:\Users\Carlos\Desktop> $var1.GetType().Name
Int32
As we can see in several of the examples we treat variables as object. We can even get the members of the object with the Get-Members cmdlet:
PS
C:\Users\Carlos\Desktop> get-variable -name var2 | Get-Member TypeName: System.Management.Automation.PSVariable Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() IsValidValue Method bool IsValidValue(System.Object value) ToString Method string ToString() Attributes Property System.Collections.ObjectModel.Collection`1[[System.Attribute, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] Attributes {get;} Description Property System.String Description {get;set;} Module Property System.Management.Automation.PSModuleInfo Module {get;} ModuleName Property System.String ModuleName {get;} Name Property System.String Name {get;} Options Property System.Management.Automation.ScopedItemOptions Options {get;set;} Value Property System.Object Value {get;set;} Visibility Property System.Management.Automation.SessionStateEntryVisibility Visibility {get;set;}
Just like objects if the property allows us to set it’s value we can change it:
PS
C:\Users\Carlos\Desktop> $srvs = Get-ServicePS C:\Users\Carlos\Desktop> (get-variable srvs).Description = "This variable contains the services objects"PS C:\Users\Carlos\Desktop> get-variable srvs | select name,description | ft –AutoSizeName Description ---- ----------- srvs This variable contains the services objects
Dynamic and Static Typing of Variables
PowerShell uses the .Net Framework variable types. The most common types of values we can have in a variable are shown in the table bellow:
Variable type | Description |
[array] | An array |
[bool] | Yes-no value |
[byte] | Unsigned 8-bit integer, 0...255 |
[char] | Individual unicode character |
[datetime] | Date and time indications |
[decimal] | Decimal number |
[wmi] | WMI Object |
[double] | Double-precision floating point decimal |
[guid] | Globally unambiguous 32-byte identification number |
[hashtable] | Hash table |
[int16] | 16-bit integer with characters |
[int32], [int] | 32-bit integers with characters |
[int64], [long] | 64-bit integers with characters |
[nullable] | Widens another data type to include the ability to contain null values. |
[psobject] | PowerShell object |
[regex] | Regular expression |
[sbyte] | 8-bit integers with characters |
[scriptblock] | PowerShell scriptblock |
[single], [float] | Single-precision floating point number |
[string] | String |
[switch] | PowerShell switch parameter |
[timespan] | Time interval |
[type] | Type |
[uint16] | Unsigned 16-bit integer |
[uint32] | Unsigned 32-bit integer |
[uint64] | Unsigned 64-bit integer |
In PowerShell variables are dynamic. This means that we do not have to declare them and specify a type ahead of use and it can take any value type we want to give it.
PS
C:\Users\Carlos\Desktop> $var1 = 1PS C:\Users\Carlos\Desktop> $var1.GetType().NameInt32
PS C:\Users\Carlos\Desktop> $var1 = "string"PS C:\Users\Carlos\Desktop> $var1.GetType().NameString
PS C:\Users\Carlos\Desktop> $var1 = 1.30PS C:\Users\Carlos\Desktop> $var1.GetType().NameDouble
Now as mentioned before PowerShell variables can be dynamically typed, but we can also strong type variable by casting them using the variable type:
PS
C:\Users\Carlos\Desktop> [int32]$var2 = 10PS C:\Users\Carlos\Desktop> $var2.GetType().NameInt32
PS C:\Users\Carlos\Desktop> $var2 = "hello"Cannot convert value "hello" to type "System.Int32". Error: "Input string was not in a correct format." At line:1 char:6 + $var2 <<<< = "hello" + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException
As we can see we got an error when we tried to save a string to the variable. The type is set in the Attribute property of the variable and if we remove the attribute it will become a dynamic variable again.
Variable Options and Attributes
We can also mark variables as read only using the SetVariable cmdlet on existing variables or when creating them with the New-Variable cmdlet:
PS
C:\Users\Carlos\Desktop> Set-Variable -Name var2 -Option ReadOnlyPS C:\Users\Carlos\Desktop> $var2 = 20Cannot overwrite variable var2 because it is read-only or constant. At line:1 char:6 + $var2 <<<< = 20 + CategoryInfo : WriteError: (var2:String) [], SessionStateUnauthorizedAccessException + FullyQualifiedErrorId : VariableNotWritable
As we can see we could not change the value on a ReadOnly variable by using assignment. But we can change it using the Set-Variable cmdlet and giving it the parameter of –Force:
PS
C:\Users\Carlos\Desktop> Set-Variable -Name var2 -Value 20 -ForcePS C:\Users\Carlos\Desktop> $var220
If we want an immutable variable we have to create the variable as a Constant. By declaring it as one it can not be deleted, changed nor cleared during the duration of a session.
For clearing a variable we can use the Clear-Variable cmdlet or assign to it the $null value ($null is an Automatic variable created by PowerShell at startup of a session)
PS
C:\Users\Carlos\Desktop> $testvar = "hello"PS C:\Users\Carlos\Desktop> $testvarhello
PS C:\Users\Carlos\Desktop> Clear-Variable testvarPS C:\Users\Carlos\Desktop> $testvarPS C:\Users\Carlos\Desktop>
We can also treat it as file (Child-Item) in a file system in the variables PSDrive:
PS
C:\Users\Carlos\Desktop> $testvar = "hello"PS C:\Users\Carlos\Desktop> Get-Content Variable:\testvarhello
PS C:\Users\Carlos\Desktop> Set-Content -Value $null -Path Variable:\testvarPS C:\Users\Carlos\Desktop> Get-Content Variable:\testvarPS C:\Users\Carlos\Desktop>
We can also use assignment to clear the variable this is done by assigning $null to it:
PS
C:\Users\Carlos\Desktop> $var4 = "PS Rocks!"PS C:\Users\Carlos\Desktop> $var4 = $nullPS C:\Users\Carlos\Desktop> $var4PS C:\Users\Carlos\Desktop>
To delete a variable we use the Remove-Variable cmdlet and it will be deleted from the current session:
PS C:\Users\Carlos\Desktop> Remove-Variable var4 PS C:\Users\Carlos\Desktop> dir variable:\var* Name Value ---- ----- var1 1.3 var2 20
If a Variable has an option of ReadOnly we can remove it by passing the parameter of –Force to the Remove-Variable cmdlet.
Variables in PowerShell can have several attributes that will control not only the variable type it will accept but other restrictions we might want to impose upon them. Attributes are saved as an Array in the property which allows us to have several attributes assigned to the variable object. Lets look at the attributes of $var2:
# We get the variable object first in to another variable to make it easier to manipulatePS
C:\Users\Carlos\Desktop> $avar = Get-Variable var2# Lets get members of the variablePS
C:\Users\Carlos\Desktop> $avar | Get-Member TypeName: System.Management.Automation.PSVariable Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() IsValidValue Method bool IsValidValue(System.Object value) ToString Method string ToString() Attributes Property System.Collections.ObjectModel.Collection`1[[System.Attribute, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] Attributes {get;} Description Property System.String Description {get;set;} Module Property System.Management.Automation.PSModuleInfo Module {get;} ModuleName Property System.String ModuleName {get;} Name Property System.String Name {get;} Options Property System.Management.Automation.ScopedItemOptions Options {get;set;} Value Property System.Object Value {get;set;} Visibility Property System.Management.Automation.SessionStateEntryVisibility Visibility {get;set;} #Lets get the attribute propertyPS
C:\Users\Carlos\Desktop> $avar.Attributes TypeId ------ System.Management.Automation.ArgumentTypeConverterAttribute
The attributes we can set are:
- System.Management.Automation. ValidateSetAttribute – The value may have only a given set of values.
- System.Management.Automation. ValidateRangeAttribute – The value must match a particular number range.
- System.Management.Automation. ValidatePatternAttribute – The value must match a Regular Expression.
- System.Management.Automation.ValidateNotNullOrEmptyAttribute –The value may not be zero or empty ($null).
- System.Management.Automation. ValidateNotNullAttribute – The value may not be zero.
- System.Management.Automation. ValidateLengthAttribute – The value must be in a specified range given a minimum and maximum length.
The attributes must be objects and they are set using the method of Attribute.Add() and we pass as an argument a new object created with the New-Object cmdlet. Lets start by clearing the attribute for Int types.
PS
C:\Users\Carlos\Desktop> $avar.Attributes.Clear()PS C:\Users\Carlos\Desktop> $avar.AttributesPS C:\Users\Carlos\Desktop>
Let make a variable only take a Range:
PS
C:\Users\Carlos\Desktop>$var2 = 5 PS C:\Users\Carlos\Desktop> $avar.Attributes.Add($(New-Object System.Management.Automation.ValidateRangeAttribute -argumentList 1,20))PS C:\Users\Carlos\Desktop> $var2 = 1PS C:\Users\Carlos\Desktop> $var2 = 22The variable cannot be validated because the value 22 is not a valid value
for the var2 variable.At line:1 char:6
+ $var2 <<<< = 22+ CategoryInfo : MetadataError: (:) [], ValidationMetadataException+ FullyQualifiedErrorId : ValidateSetFailure
Lets look now at setting a set of approved values:
PS
C:\Users\Carlos\Desktop> $var2 = "yes"PS C:\Users\Carlos\Desktop> $avar = Get-Variable var2PS C:\Users\Carlos\Desktop> $avar.Attributes.Add($(New-Object System.Management.Automation.ValidateSetAttribute -argumentList "yes", "no", "y", "n"))PS C:\Users\Carlos\Desktop> $var2 = "no"PS C:\Users\Carlos\Desktop> $var2 = "y"PS C:\Users\Carlos\Desktop> $var2 = "n"PS C:\Users\Carlos\Desktop> $var2 = "si"The variable cannot be validated because the value si is not a valid value for the var2 variable. At line:1 char:6 + $var2 <<<< = "si" + CategoryInfo : MetadataError: (:) [], ValidationMetadataException + FullyQualifiedErrorId : ValidateSetFailure
Lets set a pattern to match a string starting with a specific string. The pattern should be a regular expression:
PS
C:\Users\Carlos\Desktop> $pattern_var = "PS Rocks uhmmm"PS C:\Users\Carlos\Desktop> $pvar = Get-Variable pattern_varPS C:\Users\Carlos\Desktop> $pattern = "PS Rocks*"PS C:\Users\Carlos\Desktop> $pvar.Attributes.Add($(New-Object System.Management.Automation.ValidatePatternAttribute -ArgumentList $pattern))PS C:\Users\Carlos\Desktop> $pattern_var = "PS Sucks!"The variable cannot be validated because the value
PS Sucks! is not a valid value for the pattern_var variable.At line:1 char:13
+ $pattern_var <<<< = "PS Sucks!"+ CategoryInfo : MetadataError: (:) [], ValidationMetadataException+ FullyQualifiedErrorId : ValidateSetFailure
Lets look at validating a length from 1 to 8:
PS
C:\Users\Carlos\Desktop> $length_var = "1234"PS C:\Users\Carlos\Desktop> $lvar = Get-Variable length_varPS C:\Users\Carlos\Desktop> $lvar.Attributes.Add($(New-Object System.Management.Automation.ValidateLengthAttribute -ArgumentList 1,8))PS C:\Users\Carlos\Desktop> $length_var = "Hello I'm longer than 8 chars"The variable cannot be validated because the value Hello I
'm longer than 8 chars is not a valid value for the length_var variable.At line:1 char:12
+ $length_var <<<< = "Hello I'
m longer than 8 chars"+ CategoryInfo : MetadataError: (:) [], ValidationMetadataException
+ FullyQualifiedErrorId : ValidateSetFailure
For the other attributes of Null and Empty checking we just create the object with no arguments and pass it as an attribute.
Variable Scopes
Just like with any other shell that supports scripting and most modern scripting languages variables will have a scope. Scope is in what parts of a session or script the variable is available to us for use. In PowerShell the scopes are:
- $global – Variables are accessible to scripts, function and to any cmdlet in the current session.
- $script – Variables are only accessible inside the running context of the script and are discarded after the script finishes executing.
- $private – Variables are valid only in the current scope, either a script or a function. They cannot be passed to other scopes.
- $local – Variables are valid only in the current scope of the script or session. All scopes called with them can read, but not change, the contents of the variable and it is the default when creating a variable.
to declare a variable in an scope other than local scope we do it by appending to the beginning of the variable declaration the scope:
# Declaring the variable
PS C:\Users\Carlos\Desktop> $global:gvar = "This is a global variable"PS C:\Users\Carlos\Desktop> $gvarThis is a global variable
# Using the New-Variable cmdletPS C:\Users\Carlos\Desktop> $global:gvar = "This is a global variable"PS C:\Users\Carlos\Desktop> $gvarThis is a global variable
Automatic Variables
Automatic variables are created and populated when the session is launched. These variables will contain user information, system information, default variables, run time variables and settings for PowerShell. To get a look at the variables and what they do we can either do Get-Help about_Automatic_Variables or list the variables and select only the name and description as shown bellow:
PS
C:\Users\Carlos> Get-Variable | select name,description | ft -AutoSize -Wrap Name Description ---- ----------- $ ? Execution status of last command. ^ _ args ConfirmPreference Dictates when confirmation should be requested. Confirmation is requested when the Confir mImpact of the operation is equal to or greater than $ConfirmPreference. If $ConfirmPrefe rence is None, actions will only be confirmed when Confirm is specified. ConsoleFileName Name of the current console file. DebugPreference Dictates action taken when an Debug message is delivered. Error ErrorActionPreference Dictates action taken when an Error message is delivered. ErrorView Dictates the view mode to use when displaying errors. ExecutionContext The execution objects available to cmdlets. false Boolean False FormatEnumerationLimit Dictates the limit of enumeration on formatting IEnumerable objects. HOME Folder containing the current user's profile. Host This is a reference to the host of this Runspace. input MaximumAliasCount The maximum number of aliases allowed in a session. MaximumDriveCount The maximum number of drives allowed in a session. MaximumErrorCount The maximum number of errors to retain in a session. MaximumFunctionCount The maximum number of functions allowed in a session. MaximumHistoryCount The maximum number of history objects to retain in a session. MaximumVariableCount The maximum number of variables allowed in a session. MyInvocation NestedPromptLevel Dictates what type of prompt should be displayed for the current nesting level. null References to the null variable always return the null value. Assignments have no effect. OutputEncoding The text encoding used when piping text to a native executable. PID Current process ID. PROFILE ProgressPreference Dictates action taken when Progress Records are delivered. PSBoundParameters PSCulture Culture of the current Windows PowerShell Session. PSEmailServer Variable to hold the Email Server. This can be used instead of HostName parameter in Send -MailMessage cmdlet. PSHOME Parent folder of the host application of this Runspace. PSSessionApplicationName AppName where the remote connection will be established PSSessionConfigurationName Name of the session configuration which will be loaded on the remote computer PSSessionOption Default session options for new remote sessions. PSUICulture UI Culture of the current Windows PowerShell Session. PSVersionTable Version information for current PowerShell session. PWD ReportErrorShowExceptionClass Causes errors to be displayed with a description of the error class. ReportErrorShowInnerException Causes errors to be displayed with the inner exceptions. ReportErrorShowSource Causes errors to be displayed with the source of the error. ReportErrorShowStackTrace Causes errors to be displayed with a stack trace. ShellId The ShellID identifies the current shell. This is used by #Requires. StackTrace true Boolean True VerbosePreference Dictates the action taken when a Verbose message is delivered. WarningPreference Dictates the action taken when a Warning message is delivered. WhatIfPreference If true, WhatIf is considered to be enabled for all commands.
One of the variables you might find your self using is to check if the last cmdlet you invoked ran successfully or not, the exit state is saved in $? with a value of False if it failed and True if it was successful.
PS
C:\Users\Carlos\Desktop> Get-nonexistingcmdletThe term
'Get-nonexistingcmdlet' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the pathis correct and
try again.At line:1 char:22
+ Get-nonexistingcmdlet <<<<+ CategoryInfo : ObjectNotFound: (Get-nonexistingcmdlet:String) [], CommandNotFoundException+ FullyQualifiedErrorId : CommandNotFoundExceptionPS C:\Users\Carlos\Desktop> $?False
PS C:\Users\Carlos\Desktop> Get-Variable pshomeName Value
--
-- -----PSHOME C:\Windows\System32\WindowsPowerShell\v1.0
PS C:\Users\Carlos\Desktop> $?True
If we are executing system executable the variable with the last exit code would be $lastexitcode returning the exit code for the error found when executing or 0 if it executed successfully.
PS
C:\Users\Carlos\Desktop> wmic systemdrivesystemdrive
- Alias not found.PS C:\Users\Carlos\Desktop> $LASTEXITCODE44135
PS C:\Users\Carlos\Desktop> hostnameinfidel01
PS C:\Users\Carlos\Desktop> $LASTEXITCODE0
Some of the automatic variables can be changed so as to customize the session, others are read only and others are modified by the session it self as it executes. Many of these variable will prove useful as you work with PowerShell so I invite you to read the help on automatic variables.
Conclusion
I only covered some of the main points of variables and how to work with them. I do invite you to read more about them in the internal documentation that Microsoft PowerShell provides using the Get-Help cmdlet:
- about_Variables
- about_Automatic_Variables
- about_Environment_Variables
- about_Preference_Variables
- about_Scopes
As always I hope you find this blog post useful and informative.